From e3ea1b4847e49234e691c0d66bf030bd65bb7f2b Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Sat, 12 Nov 2022 17:25:41 +0800 Subject: [PATCH 0001/1451] pcmcia: cs: fix possible hung task and memory leak pccardd() If device_register() returns error in pccardd(), it leads two issues: 1. The socket_released has never been completed, it will block pcmcia_unregister_socket(), because of waiting for completion of socket_released. 2. The device name allocated by dev_set_name() is leaked. Fix this two issues by calling put_device() when device_register() fails. socket_released can be completed in pcmcia_release_socket(), the name can be freed in kobject_cleanup(). Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Yang Yingliang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 5658745c398f5..b33be1e63c98f 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -605,6 +605,7 @@ static int pccardd(void *__skt) dev_warn(&skt->dev, "PCMCIA: unable to register socket\n"); skt->thread = NULL; complete(&skt->thread_done); + put_device(&skt->dev); return 0; } ret = pccard_sysfs_add_socket(&skt->dev); -- GitLab From 402ab979b29126068e0b596b641422ff7490214c Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Sat, 12 Nov 2022 17:29:23 +0800 Subject: [PATCH 0002/1451] pcmcia: ds: fix refcount leak in pcmcia_device_add() As the comment of device_register() says, it should use put_device() to give up the reference in the error path. Then, insofar resources will be freed in pcmcia_release_dev(), the error path is no longer needed. In particular, this means that the (previously missing) dropping of the reference to &p_dev->function_config->ref is now handled by pcmcia_release_dev(). Fixes: 360b65b95bae ("[PATCH] pcmcia: make config_t independent, add reference counting") Signed-off-by: Yang Yingliang [linux@dominikbrodowski.net: simplification, commit message rewrite] Signed-off-by: Dominik Brodowski --- drivers/pcmcia/ds.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index d500e5dbbc3f5..c90c68dee1e45 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -573,8 +573,14 @@ static struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, pcmcia_device_query(p_dev); - if (device_register(&p_dev->dev)) - goto err_unreg; + if (device_register(&p_dev->dev)) { + mutex_lock(&s->ops_mutex); + list_del(&p_dev->socket_device_list); + s->device_count--; + mutex_unlock(&s->ops_mutex); + put_device(&p_dev->dev); + return NULL; + } return p_dev; -- GitLab From 99e1241049a92dd3e9a90a0f91e32ce390133278 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Sat, 12 Nov 2022 17:29:24 +0800 Subject: [PATCH 0003/1451] pcmcia: ds: fix possible name leak in error path in pcmcia_device_add() Afer commit 1fa5ae857bb1 ("driver core: get rid of struct device's bus_id string array"), the name of device is allocated dynamically. Therefore, it needs to be freed, which is done by the driver core for us once all references to the device are gone. Therefore, move the dev_set_name() call immediately before the call device_register(), which either succeeds (then the freeing will be done upon subsequent remvoal), or puts the reference in the error call. Also, it is not unusual that the return value of dev_set_name is not checked. Fixes: 1fa5ae857bb1 ("driver core: get rid of struct device's bus_id string array") Signed-off-by: Yang Yingliang [linux@dominikbrodowski.net: simplification, commit message modified] Signed-off-by: Dominik Brodowski --- drivers/pcmcia/ds.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index c90c68dee1e45..b4b8363d1de21 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -513,9 +513,6 @@ static struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, /* by default don't allow DMA */ p_dev->dma_mask = 0; p_dev->dev.dma_mask = &p_dev->dma_mask; - dev_set_name(&p_dev->dev, "%d.%d", p_dev->socket->sock, p_dev->device_no); - if (!dev_name(&p_dev->dev)) - goto err_free; p_dev->devname = kasprintf(GFP_KERNEL, "pcmcia%s", dev_name(&p_dev->dev)); if (!p_dev->devname) goto err_free; @@ -573,6 +570,7 @@ static struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, pcmcia_device_query(p_dev); + dev_set_name(&p_dev->dev, "%d.%d", p_dev->socket->sock, p_dev->device_no); if (device_register(&p_dev->dev)) { mutex_lock(&s->ops_mutex); list_del(&p_dev->socket_device_list); -- GitLab From 99e25b17d2a3e3b486b4f6f90a740d51245da1f2 Mon Sep 17 00:00:00 2001 From: Dongliang Mu Date: Wed, 16 Nov 2022 09:45:50 +0800 Subject: [PATCH 0004/1451] pcmcia: typo fix themselfves -> themselves Signed-off-by: Dongliang Mu Signed-off-by: Dominik Brodowski --- drivers/pcmcia/pcmcia_resource.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index d78091e79a0f6..e9e31c638a671 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -684,7 +684,7 @@ EXPORT_SYMBOL(pcmcia_request_io); * pcmcia_request_irq() is a wrapper around request_irq() which allows * the PCMCIA core to clean up the registration in pcmcia_disable_device(). * Drivers are free to use request_irq() directly, but then they need to - * call free_irq() themselfves, too. Also, only %IRQF_SHARED capable IRQ + * call free_irq() themselves, too. Also, only %IRQF_SHARED capable IRQ * handlers are allowed. */ int __must_check pcmcia_request_irq(struct pcmcia_device *p_dev, -- GitLab From 4f733de8b78a209501041a4b0a44c83ece0e8933 Mon Sep 17 00:00:00 2001 From: lizhe Date: Tue, 20 Dec 2022 22:37:49 -0800 Subject: [PATCH 0005/1451] pcmcia: tcic: remove unneeded "&" in call to setup_timer() The second parameter is the entry address of the function, and therefore does not require an "&". Signed-off-by: lizhe [linux@dominikbrodowski.net: update commit message] Signed-off-by: Dominik Brodowski --- drivers/pcmcia/tcic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index 1a0e3f0987599..5ef888688e231 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -435,7 +435,7 @@ static int __init init_tcic(void) } /* Set up polling */ - timer_setup(&poll_timer, &tcic_timer, 0); + timer_setup(&poll_timer, tcic_timer, 0); /* Build interrupt mask */ printk(KERN_CONT ", %d sockets\n", sockets); -- GitLab From 99faa48a5de31b360de22a7134291a110171d3f0 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:10 -0700 Subject: [PATCH 0006/1451] Input: cros_ec_keyb - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Reviewed-by: Guenter Roeck Reviewed-by: Greg Kroah-Hartman Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-1-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/cros_ec_keyb.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index e7ecfca838df4..313b7a69dd692 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c @@ -686,10 +686,11 @@ static umode_t cros_ec_keyb_attr_is_visible(struct kobject *kobj, return attr->mode; } -static const struct attribute_group cros_ec_keyb_attr_group = { +static const struct attribute_group cros_ec_keyb_group = { .is_visible = cros_ec_keyb_attr_is_visible, .attrs = cros_ec_keyb_attrs, }; +__ATTRIBUTE_GROUPS(cros_ec_keyb); static int cros_ec_keyb_probe(struct platform_device *pdev) { @@ -730,12 +731,6 @@ static int cros_ec_keyb_probe(struct platform_device *pdev) return err; } - err = devm_device_add_group(dev, &cros_ec_keyb_attr_group); - if (err) { - dev_err(dev, "failed to create attributes: %d\n", err); - return err; - } - ckdev->notifier.notifier_call = cros_ec_keyb_work; err = blocking_notifier_chain_register(&ckdev->ec->event_notifier, &ckdev->notifier); @@ -782,6 +777,7 @@ static struct platform_driver cros_ec_keyb_driver = { .remove = cros_ec_keyb_remove, .driver = { .name = "cros-ec-keyb", + .dev_groups = cros_ec_keyb_groups, .of_match_table = of_match_ptr(cros_ec_keyb_of_match), .acpi_match_table = ACPI_PTR(cros_ec_keyb_acpi_match), .pm = pm_sleep_ptr(&cros_ec_keyb_pm_ops), -- GitLab From 4cd121c19a30bd3f5f84612313e94828edf6a91b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:11 -0700 Subject: [PATCH 0007/1451] Input: cyapa - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-2-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/cyapa.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index 05851bc32541f..a84098448f5b9 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -1223,7 +1223,7 @@ static DEVICE_ATTR(baseline, S_IRUGO, cyapa_show_baseline, NULL); static DEVICE_ATTR(calibrate, S_IWUSR, NULL, cyapa_calibrate_store); static DEVICE_ATTR(mode, S_IRUGO, cyapa_show_mode, NULL); -static struct attribute *cyapa_sysfs_entries[] = { +static struct attribute *cyapa_attrs[] = { &dev_attr_firmware_version.attr, &dev_attr_product_id.attr, &dev_attr_update_fw.attr, @@ -1232,10 +1232,7 @@ static struct attribute *cyapa_sysfs_entries[] = { &dev_attr_mode.attr, NULL, }; - -static const struct attribute_group cyapa_sysfs_group = { - .attrs = cyapa_sysfs_entries, -}; +ATTRIBUTE_GROUPS(cyapa); static void cyapa_disable_regulator(void *data) { @@ -1302,12 +1299,6 @@ static int cyapa_probe(struct i2c_client *client) return error; } - error = devm_device_add_group(dev, &cyapa_sysfs_group); - if (error) { - dev_err(dev, "failed to create sysfs entries: %d\n", error); - return error; - } - error = cyapa_prepare_wakeup_controls(cyapa); if (error) { dev_err(dev, "failed to prepare wakeup controls: %d\n", error); @@ -1484,6 +1475,7 @@ MODULE_DEVICE_TABLE(of, cyapa_of_match); static struct i2c_driver cyapa_driver = { .driver = { .name = "cyapa", + .dev_groups = cyapa_groups, .pm = pm_ptr(&cyapa_pm_ops), .acpi_match_table = ACPI_PTR(cyapa_acpi_id), .of_match_table = of_match_ptr(cyapa_of_match), -- GitLab From 09adb31f6f6cf73d9be7a695ff030144fb64c91d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:12 -0700 Subject: [PATCH 0008/1451] Input: iqs269a - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Reviewed-by: Mattijs Korpershoek Reviewed-by: Jeff LaBundy Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-3-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/misc/iqs269a.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/input/misc/iqs269a.c b/drivers/input/misc/iqs269a.c index c0a0856398705..3c636c75e8a1f 100644 --- a/drivers/input/misc/iqs269a.c +++ b/drivers/input/misc/iqs269a.c @@ -1586,10 +1586,7 @@ static struct attribute *iqs269_attrs[] = { &dev_attr_ati_trigger.attr, NULL, }; - -static const struct attribute_group iqs269_attr_group = { - .attrs = iqs269_attrs, -}; +ATTRIBUTE_GROUPS(iqs269); static const struct regmap_config iqs269_regmap_config = { .reg_bits = 8, @@ -1671,10 +1668,6 @@ static int iqs269_probe(struct i2c_client *client) return error; } - error = devm_device_add_group(&client->dev, &iqs269_attr_group); - if (error) - dev_err(&client->dev, "Failed to add attributes: %d\n", error); - return error; } @@ -1743,6 +1736,7 @@ MODULE_DEVICE_TABLE(of, iqs269_of_match); static struct i2c_driver iqs269_i2c_driver = { .driver = { .name = "iqs269a", + .dev_groups = iqs269_groups, .of_match_table = iqs269_of_match, .pm = pm_sleep_ptr(&iqs269_pm), }, -- GitLab From b4f2ad7b232a0df8f73cbde5966e4d4e5d82fc52 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:13 -0700 Subject: [PATCH 0009/1451] Input: kxtj9 - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-4-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/misc/kxtj9.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c index 912e614d039d7..d47269b10e9ab 100644 --- a/drivers/input/misc/kxtj9.c +++ b/drivers/input/misc/kxtj9.c @@ -334,14 +334,25 @@ static ssize_t kxtj9_set_poll(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(poll, S_IRUGO|S_IWUSR, kxtj9_get_poll, kxtj9_set_poll); -static struct attribute *kxtj9_attributes[] = { +static struct attribute *kxtj9_attrs[] = { &dev_attr_poll.attr, NULL }; -static struct attribute_group kxtj9_attribute_group = { - .attrs = kxtj9_attributes +static umode_t kxtj9_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct i2c_client *client = to_i2c_client(dev); + + return client->irq ? attr->mode : 0; +} + +static struct attribute_group kxtj9_group = { + .attrs = kxtj9_attrs, + .is_visible = kxtj9_attr_is_visible, }; +__ATTRIBUTE_GROUPS(kxtj9); static void kxtj9_poll(struct input_dev *input) { @@ -482,13 +493,6 @@ static int kxtj9_probe(struct i2c_client *client) dev_err(&client->dev, "request irq failed: %d\n", err); return err; } - - err = devm_device_add_group(&client->dev, - &kxtj9_attribute_group); - if (err) { - dev_err(&client->dev, "sysfs create failed: %d\n", err); - return err; - } } return 0; @@ -535,8 +539,9 @@ MODULE_DEVICE_TABLE(i2c, kxtj9_id); static struct i2c_driver kxtj9_driver = { .driver = { - .name = NAME, - .pm = pm_sleep_ptr(&kxtj9_pm_ops), + .name = NAME, + .dev_groups = kxtj9_groups, + .pm = pm_sleep_ptr(&kxtj9_pm_ops), }, .probe = kxtj9_probe, .id_table = kxtj9_id, -- GitLab From e86253d98547a2229693dc516943439513949003 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:14 -0700 Subject: [PATCH 0010/1451] Input: ad7877 - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Acked-by: Michael Hennerich Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-5-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ad7877.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c index edb36d663f22f..a0598e9c7affc 100644 --- a/drivers/input/touchscreen/ad7877.c +++ b/drivers/input/touchscreen/ad7877.c @@ -612,10 +612,11 @@ static umode_t ad7877_attr_is_visible(struct kobject *kobj, return mode; } -static const struct attribute_group ad7877_attr_group = { +static const struct attribute_group ad7877_group = { .is_visible = ad7877_attr_is_visible, .attrs = ad7877_attributes, }; +__ATTRIBUTE_GROUPS(ad7877); static void ad7877_setup_ts_def_msg(struct spi_device *spi, struct ad7877 *ts) { @@ -777,10 +778,6 @@ static int ad7877_probe(struct spi_device *spi) return err; } - err = devm_device_add_group(&spi->dev, &ad7877_attr_group); - if (err) - return err; - err = input_register_device(input_dev); if (err) return err; @@ -810,8 +807,9 @@ static DEFINE_SIMPLE_DEV_PM_OPS(ad7877_pm, ad7877_suspend, ad7877_resume); static struct spi_driver ad7877_driver = { .driver = { - .name = "ad7877", - .pm = pm_sleep_ptr(&ad7877_pm), + .name = "ad7877", + .dev_groups = ad7877_groups, + .pm = pm_sleep_ptr(&ad7877_pm), }, .probe = ad7877_probe, }; -- GitLab From a32fa4359a7b7766631549db427a183c5c6d032e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:15 -0700 Subject: [PATCH 0011/1451] Input: ad7879 - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Acked-by: Michael Hennerich Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-6-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ad7879-i2c.c | 7 ++++--- drivers/input/touchscreen/ad7879-spi.c | 7 ++++--- drivers/input/touchscreen/ad7879.c | 10 ++++++---- drivers/input/touchscreen/ad7879.h | 3 +++ 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c index feaa6f8b01ed6..5c094ab746989 100644 --- a/drivers/input/touchscreen/ad7879-i2c.c +++ b/drivers/input/touchscreen/ad7879-i2c.c @@ -58,9 +58,10 @@ MODULE_DEVICE_TABLE(of, ad7879_i2c_dt_ids); static struct i2c_driver ad7879_i2c_driver = { .driver = { - .name = "ad7879", - .pm = &ad7879_pm_ops, - .of_match_table = of_match_ptr(ad7879_i2c_dt_ids), + .name = "ad7879", + .dev_groups = ad7879_groups, + .pm = &ad7879_pm_ops, + .of_match_table = of_match_ptr(ad7879_i2c_dt_ids), }, .probe = ad7879_i2c_probe, .id_table = ad7879_id, diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c index 50e8898468003..064968fe57cfd 100644 --- a/drivers/input/touchscreen/ad7879-spi.c +++ b/drivers/input/touchscreen/ad7879-spi.c @@ -56,9 +56,10 @@ MODULE_DEVICE_TABLE(of, ad7879_spi_dt_ids); static struct spi_driver ad7879_spi_driver = { .driver = { - .name = "ad7879", - .pm = &ad7879_pm_ops, - .of_match_table = of_match_ptr(ad7879_spi_dt_ids), + .name = "ad7879", + .dev_groups = ad7879_groups, + .pm = &ad7879_pm_ops, + .of_match_table = of_match_ptr(ad7879_spi_dt_ids), }, .probe = ad7879_spi_probe, }; diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index e850853328f1b..e5d69bf2276e0 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -391,6 +391,12 @@ static const struct attribute_group ad7879_attr_group = { .attrs = ad7879_attributes, }; +const struct attribute_group *ad7879_groups[] = { + &ad7879_attr_group, + NULL +}; +EXPORT_SYMBOL_GPL(ad7879_groups); + #ifdef CONFIG_GPIOLIB static int ad7879_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) @@ -612,10 +618,6 @@ int ad7879_probe(struct device *dev, struct regmap *regmap, __ad7879_disable(ts); - err = devm_device_add_group(dev, &ad7879_attr_group); - if (err) - return err; - err = ad7879_gpio_add(ts); if (err) return err; diff --git a/drivers/input/touchscreen/ad7879.h b/drivers/input/touchscreen/ad7879.h index ae8aa1428e56b..d71a8e7872900 100644 --- a/drivers/input/touchscreen/ad7879.h +++ b/drivers/input/touchscreen/ad7879.h @@ -8,11 +8,14 @@ #ifndef _AD7879_H_ #define _AD7879_H_ +#include #include +struct attribute_group; struct device; struct regmap; +extern const struct attribute_group *ad7879_groups[]; extern const struct dev_pm_ops ad7879_pm_ops; int ad7879_probe(struct device *dev, struct regmap *regmap, -- GitLab From e9f6aa10aaa898c88d532c31277436100445f328 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:16 -0700 Subject: [PATCH 0012/1451] Input: ads7846 - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-7-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index faea40dd66d01..d2bbb436a77df 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -625,15 +625,12 @@ static ssize_t ads7846_disable_store(struct device *dev, static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store); -static struct attribute *ads784x_attributes[] = { +static struct attribute *ads784x_attrs[] = { &dev_attr_pen_down.attr, &dev_attr_disable.attr, NULL, }; - -static const struct attribute_group ads784x_attr_group = { - .attrs = ads784x_attributes, -}; +ATTRIBUTE_GROUPS(ads784x); /*--------------------------------------------------------------------------*/ @@ -1357,10 +1354,6 @@ static int ads7846_probe(struct spi_device *spi) else (void) ads7846_read12_ser(dev, READ_12BIT_SER(vaux)); - err = devm_device_add_group(dev, &ads784x_attr_group); - if (err) - return err; - err = input_register_device(input_dev); if (err) return err; @@ -1386,9 +1379,10 @@ static void ads7846_remove(struct spi_device *spi) static struct spi_driver ads7846_driver = { .driver = { - .name = "ads7846", - .pm = pm_sleep_ptr(&ads7846_pm), - .of_match_table = ads7846_dt_ids, + .name = "ads7846", + .dev_groups = ads784x_groups, + .pm = pm_sleep_ptr(&ads7846_pm), + .of_match_table = ads7846_dt_ids, }, .probe = ads7846_probe, .remove = ads7846_remove, -- GitLab From a1bdf4584565892046db6b3bf75de529d91d58ca Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:17 -0700 Subject: [PATCH 0013/1451] Input: edt-ft5x06 - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-8-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 457d53337fbb3..3e102bcc4a1c7 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -580,10 +580,7 @@ static struct attribute *edt_ft5x06_attrs[] = { &dev_attr_crc_errors.attr, NULL }; - -static const struct attribute_group edt_ft5x06_attr_group = { - .attrs = edt_ft5x06_attrs, -}; +ATTRIBUTE_GROUPS(edt_ft5x06); static void edt_ft5x06_restore_reg_parameters(struct edt_ft5x06_ts_data *tsdata) { @@ -1330,10 +1327,6 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) return error; } - error = devm_device_add_group(&client->dev, &edt_ft5x06_attr_group); - if (error) - return error; - error = input_register_device(input); if (error) return error; @@ -1502,6 +1495,7 @@ MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match); static struct i2c_driver edt_ft5x06_ts_driver = { .driver = { .name = "edt_ft5x06", + .dev_groups = edt_ft5x06_groups, .of_match_table = edt_ft5x06_of_match, .pm = pm_sleep_ptr(&edt_ft5x06_ts_pm_ops), .probe_type = PROBE_PREFER_ASYNCHRONOUS, -- GitLab From c9110729a0e36cc355173e6cd1f5a12228c38b36 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:18 -0700 Subject: [PATCH 0014/1451] Input: elants_i2c - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-9-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/elants_i2c.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index a1af3de9f3109..365765d40e627 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -1299,7 +1299,7 @@ static ELANTS_VERSION_ATTR(solution_version); static ELANTS_VERSION_ATTR(bc_version); static ELANTS_VERSION_ATTR(iap_version); -static struct attribute *elants_attributes[] = { +static struct attribute *elants_i2c_attrs[] = { &dev_attr_calibrate.attr, &dev_attr_update_fw.attr, &dev_attr_iap_mode.attr, @@ -1313,10 +1313,7 @@ static struct attribute *elants_attributes[] = { &elants_ver_attr_iap_version.dattr.attr, NULL }; - -static const struct attribute_group elants_attribute_group = { - .attrs = elants_attributes, -}; +ATTRIBUTE_GROUPS(elants_i2c); static int elants_i2c_power_on(struct elants_data *ts) { @@ -1552,13 +1549,6 @@ static int elants_i2c_probe(struct i2c_client *client) return error; } - error = devm_device_add_group(&client->dev, &elants_attribute_group); - if (error) { - dev_err(&client->dev, "failed to create sysfs attributes: %d\n", - error); - return error; - } - return 0; } @@ -1667,6 +1657,7 @@ static struct i2c_driver elants_i2c_driver = { .id_table = elants_i2c_id, .driver = { .name = DEVICE_NAME, + .dev_groups = elants_i2c_groups, .pm = pm_sleep_ptr(&elants_i2c_pm_ops), .acpi_match_table = ACPI_PTR(elants_acpi_id), .of_match_table = of_match_ptr(elants_of_match), -- GitLab From 354f1a2c170fbe5c9a6741c2c6a9ee0098c76b16 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:19 -0700 Subject: [PATCH 0015/1451] Input: exc3000 - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-10-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/exc3000.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/input/touchscreen/exc3000.c b/drivers/input/touchscreen/exc3000.c index e3f6d21b3c1b3..654845c0cdcd7 100644 --- a/drivers/input/touchscreen/exc3000.c +++ b/drivers/input/touchscreen/exc3000.c @@ -324,16 +324,13 @@ static ssize_t type_show(struct device *dev, } static DEVICE_ATTR_RO(type); -static struct attribute *sysfs_attrs[] = { +static struct attribute *exc3000_attrs[] = { &dev_attr_fw_version.attr, &dev_attr_model.attr, &dev_attr_type.attr, NULL }; - -static struct attribute_group exc3000_attribute_group = { - .attrs = sysfs_attrs -}; +ATTRIBUTE_GROUPS(exc3000); static int exc3000_probe(struct i2c_client *client) { @@ -436,10 +433,6 @@ static int exc3000_probe(struct i2c_client *client) i2c_set_clientdata(client, data); - error = devm_device_add_group(&client->dev, &exc3000_attribute_group); - if (error) - return error; - return 0; } @@ -464,6 +457,7 @@ MODULE_DEVICE_TABLE(of, exc3000_of_match); static struct i2c_driver exc3000_driver = { .driver = { .name = "exc3000", + .dev_groups = exc3000_groups, .of_match_table = of_match_ptr(exc3000_of_match), }, .id_table = exc3000_id, -- GitLab From 12f2288b0b635476f022597a8474a4aca8d9c0d6 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:20 -0700 Subject: [PATCH 0016/1451] Input: hideep - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-11-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/hideep.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c index 404153338df71..0f58258306bfc 100644 --- a/drivers/input/touchscreen/hideep.c +++ b/drivers/input/touchscreen/hideep.c @@ -954,16 +954,13 @@ static DEVICE_ATTR(version, 0664, hideep_fw_version_show, NULL); static DEVICE_ATTR(product_id, 0664, hideep_product_id_show, NULL); static DEVICE_ATTR(update_fw, 0664, NULL, hideep_update_fw); -static struct attribute *hideep_ts_sysfs_entries[] = { +static struct attribute *hideep_ts_attrs[] = { &dev_attr_version.attr, &dev_attr_product_id.attr, &dev_attr_update_fw.attr, NULL, }; - -static const struct attribute_group hideep_ts_attr_group = { - .attrs = hideep_ts_sysfs_entries, -}; +ATTRIBUTE_GROUPS(hideep_ts); static void hideep_set_work_mode(struct hideep_ts *ts) { @@ -1096,13 +1093,6 @@ static int hideep_probe(struct i2c_client *client) return error; } - error = devm_device_add_group(&client->dev, &hideep_ts_attr_group); - if (error) { - dev_err(&client->dev, - "failed to add sysfs attributes: %d\n", error); - return error; - } - return 0; } @@ -1131,6 +1121,7 @@ MODULE_DEVICE_TABLE(of, hideep_match_table); static struct i2c_driver hideep_driver = { .driver = { .name = HIDEEP_I2C_NAME, + .dev_groups = hideep_ts_groups, .of_match_table = of_match_ptr(hideep_match_table), .acpi_match_table = ACPI_PTR(hideep_acpi_id), .pm = pm_sleep_ptr(&hideep_pm_ops), -- GitLab From d9d538cac29a8e60a8461003b449b52201b4131c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:21 -0700 Subject: [PATCH 0017/1451] Input: hycon-hy46xx - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-12-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/hycon-hy46xx.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/input/touchscreen/hycon-hy46xx.c b/drivers/input/touchscreen/hycon-hy46xx.c index 2450cfa14de9d..d0f257989fd6b 100644 --- a/drivers/input/touchscreen/hycon-hy46xx.c +++ b/drivers/input/touchscreen/hycon-hy46xx.c @@ -274,10 +274,7 @@ static struct attribute *hycon_hy46xx_attrs[] = { &hycon_hy46xx_attr_bootloader_version.dattr.attr, NULL }; - -static const struct attribute_group hycon_hy46xx_attr_group = { - .attrs = hycon_hy46xx_attrs, -}; +ATTRIBUTE_GROUPS(hycon_hy46xx); static void hycon_hy46xx_get_defaults(struct device *dev, struct hycon_hy46xx_data *tsdata) { @@ -535,10 +532,6 @@ static int hycon_hy46xx_probe(struct i2c_client *client) return error; } - error = devm_device_add_group(&client->dev, &hycon_hy46xx_attr_group); - if (error) - return error; - error = input_register_device(input); if (error) return error; @@ -576,6 +569,7 @@ MODULE_DEVICE_TABLE(of, hycon_hy46xx_of_match); static struct i2c_driver hycon_hy46xx_driver = { .driver = { .name = "hycon_hy46xx", + .dev_groups = hycon_hy46xx_groups, .of_match_table = hycon_hy46xx_of_match, .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, -- GitLab From 6a539138be69ae814e332556663f639d4ac31880 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:22 -0700 Subject: [PATCH 0018/1451] Input: ili210x - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-13-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ili210x.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index ad6828e4f2e2d..31ffdc2a93f35 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -876,7 +876,7 @@ static ssize_t ili210x_firmware_update_store(struct device *dev, static DEVICE_ATTR(firmware_update, 0200, NULL, ili210x_firmware_update_store); -static struct attribute *ili210x_attributes[] = { +static struct attribute *ili210x_attrs[] = { &dev_attr_calibrate.attr, &dev_attr_firmware_update.attr, &dev_attr_firmware_version.attr, @@ -904,10 +904,11 @@ static umode_t ili210x_attributes_visible(struct kobject *kobj, return attr->mode; } -static const struct attribute_group ili210x_attr_group = { - .attrs = ili210x_attributes, +static const struct attribute_group ili210x_group = { + .attrs = ili210x_attrs, .is_visible = ili210x_attributes_visible, }; +__ATTRIBUTE_GROUPS(ili210x); static void ili210x_power_down(void *data) { @@ -1013,13 +1014,6 @@ static int ili210x_i2c_probe(struct i2c_client *client) if (error) return error; - error = devm_device_add_group(dev, &ili210x_attr_group); - if (error) { - dev_err(dev, "Unable to create sysfs attributes, err: %d\n", - error); - return error; - } - error = input_register_device(priv->input); if (error) { dev_err(dev, "Cannot register input device, err: %d\n", error); @@ -1050,6 +1044,7 @@ MODULE_DEVICE_TABLE(of, ili210x_dt_ids); static struct i2c_driver ili210x_ts_driver = { .driver = { .name = "ili210x_i2c", + .dev_groups = ili210x_groups, .of_match_table = ili210x_dt_ids, }, .id_table = ili210x_i2c_id, -- GitLab From e6ed1bf97ebc29542789fc5813c0fdda420bdd2c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:23 -0700 Subject: [PATCH 0019/1451] Input: ilitek_ts_i2c - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-14-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ilitek_ts_i2c.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/input/touchscreen/ilitek_ts_i2c.c b/drivers/input/touchscreen/ilitek_ts_i2c.c index 2f872e95fbbad..90c4934e750a3 100644 --- a/drivers/input/touchscreen/ilitek_ts_i2c.c +++ b/drivers/input/touchscreen/ilitek_ts_i2c.c @@ -537,10 +537,7 @@ static struct attribute *ilitek_sysfs_attrs[] = { &dev_attr_product_id.attr, NULL }; - -static struct attribute_group ilitek_attrs_group = { - .attrs = ilitek_sysfs_attrs, -}; +ATTRIBUTE_GROUPS(ilitek_sysfs); static int ilitek_ts_i2c_probe(struct i2c_client *client) { @@ -595,12 +592,6 @@ static int ilitek_ts_i2c_probe(struct i2c_client *client) return error; } - error = devm_device_add_group(dev, &ilitek_attrs_group); - if (error) { - dev_err(dev, "sysfs create group failed: %d\n", error); - return error; - } - return 0; } @@ -675,6 +666,7 @@ MODULE_DEVICE_TABLE(of, ilitek_ts_i2c_match); static struct i2c_driver ilitek_ts_i2c_driver = { .driver = { .name = ILITEK_TS_NAME, + .dev_groups = ilitek_sysfs_groups, .pm = pm_sleep_ptr(&ilitek_pm_ops), .of_match_table = of_match_ptr(ilitek_ts_i2c_match), .acpi_match_table = ACPI_PTR(ilitekts_acpi_id), -- GitLab From 2883d4e30bd7417eae570223a6db180af30e8fa7 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:24 -0700 Subject: [PATCH 0020/1451] Input: iqs5xx - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Reviewed-by: Jeff LaBundy Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-15-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/iqs5xx.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index b4768b66eb101..a3f4fb85bee58 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -974,10 +974,11 @@ static umode_t iqs5xx_attr_is_visible(struct kobject *kobj, return attr->mode; } -static const struct attribute_group iqs5xx_attr_group = { +static const struct attribute_group iqs5xx_group = { .is_visible = iqs5xx_attr_is_visible, .attrs = iqs5xx_attrs, }; +__ATTRIBUTE_GROUPS(iqs5xx); static int iqs5xx_suspend(struct device *dev) { @@ -1053,12 +1054,6 @@ static int iqs5xx_probe(struct i2c_client *client) return error; } - error = devm_device_add_group(&client->dev, &iqs5xx_attr_group); - if (error) { - dev_err(&client->dev, "Failed to add attributes: %d\n", error); - return error; - } - if (iqs5xx->input) { error = input_register_device(iqs5xx->input); if (error) @@ -1089,6 +1084,7 @@ MODULE_DEVICE_TABLE(of, iqs5xx_of_match); static struct i2c_driver iqs5xx_i2c_driver = { .driver = { .name = "iqs5xx", + .dev_groups = iqs5xx_groups, .of_match_table = iqs5xx_of_match, .pm = pm_sleep_ptr(&iqs5xx_pm), }, -- GitLab From 33478a9257b2b78dc8f3882049689e0a07909593 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:25 -0700 Subject: [PATCH 0021/1451] Input: melfas-mip4 - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-16-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/melfas_mip4.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c index 2ac4483fbc258..aa325486f6182 100644 --- a/drivers/input/touchscreen/melfas_mip4.c +++ b/drivers/input/touchscreen/melfas_mip4.c @@ -1419,10 +1419,7 @@ static struct attribute *mip4_attrs[] = { &dev_attr_update_fw.attr, NULL, }; - -static const struct attribute_group mip4_attr_group = { - .attrs = mip4_attrs, -}; +ATTRIBUTE_GROUPS(mip4); static int mip4_probe(struct i2c_client *client) { @@ -1514,13 +1511,6 @@ static int mip4_probe(struct i2c_client *client) return error; } - error = devm_device_add_group(&client->dev, &mip4_attr_group); - if (error) { - dev_err(&client->dev, - "Failed to create sysfs attribute group: %d\n", error); - return error; - } - return 0; } @@ -1589,6 +1579,7 @@ static struct i2c_driver mip4_driver = { .probe = mip4_probe, .driver = { .name = MIP4_DEVICE_NAME, + .dev_groups = mip4_groups, .of_match_table = of_match_ptr(mip4_of_match), .acpi_match_table = ACPI_PTR(mip4_acpi_match), .pm = pm_sleep_ptr(&mip4_pm_ops), -- GitLab From 4f17340909098545845fb5aad4a5bc6010f6362d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:26 -0700 Subject: [PATCH 0022/1451] Input: raydium_i2c_ts - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-17-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/raydium_i2c_ts.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c index 78dd3059d585a..13c500e776f6d 100644 --- a/drivers/input/touchscreen/raydium_i2c_ts.c +++ b/drivers/input/touchscreen/raydium_i2c_ts.c @@ -1004,7 +1004,7 @@ static DEVICE_ATTR(boot_mode, S_IRUGO, raydium_i2c_boot_mode_show, NULL); static DEVICE_ATTR(update_fw, S_IWUSR, NULL, raydium_i2c_update_fw_store); static DEVICE_ATTR(calibrate, S_IWUSR, NULL, raydium_i2c_calibrate_store); -static struct attribute *raydium_i2c_attributes[] = { +static struct attribute *raydium_i2c_attrs[] = { &dev_attr_update_fw.attr, &dev_attr_boot_mode.attr, &dev_attr_fw_version.attr, @@ -1012,10 +1012,7 @@ static struct attribute *raydium_i2c_attributes[] = { &dev_attr_calibrate.attr, NULL }; - -static const struct attribute_group raydium_i2c_attribute_group = { - .attrs = raydium_i2c_attributes, -}; +ATTRIBUTE_GROUPS(raydium_i2c); static int raydium_i2c_power_on(struct raydium_data *ts) { @@ -1174,14 +1171,6 @@ static int raydium_i2c_probe(struct i2c_client *client) return error; } - error = devm_device_add_group(&client->dev, - &raydium_i2c_attribute_group); - if (error) { - dev_err(&client->dev, "failed to create sysfs attributes: %d\n", - error); - return error; - } - return 0; } @@ -1265,6 +1254,7 @@ static struct i2c_driver raydium_i2c_driver = { .id_table = raydium_i2c_id, .driver = { .name = "raydium_ts", + .dev_groups = raydium_i2c_groups, .pm = pm_sleep_ptr(&raydium_i2c_pm_ops), .acpi_match_table = ACPI_PTR(raydium_acpi_id), .of_match_table = of_match_ptr(raydium_of_match), -- GitLab From 3837a4b9384c7e890cd87c39be53486b99ecc8a3 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:27 -0700 Subject: [PATCH 0023/1451] Input: rohm_bu21023 - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-18-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/rohm_bu21023.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/input/touchscreen/rohm_bu21023.c b/drivers/input/touchscreen/rohm_bu21023.c index 240424f06b98f..4493ad0c93221 100644 --- a/drivers/input/touchscreen/rohm_bu21023.c +++ b/drivers/input/touchscreen/rohm_bu21023.c @@ -854,10 +854,7 @@ static struct attribute *rohm_ts_attrs[] = { &dev_attr_inv_y.attr, NULL, }; - -static const struct attribute_group rohm_ts_attr_group = { - .attrs = rohm_ts_attrs, -}; +ATTRIBUTE_GROUPS(rohm_ts); static int rohm_ts_device_init(struct i2c_client *client, u8 setup2) { @@ -1164,12 +1161,6 @@ static int rohm_bu21023_i2c_probe(struct i2c_client *client) return error; } - error = devm_device_add_group(dev, &rohm_ts_attr_group); - if (error) { - dev_err(dev, "failed to create sysfs group: %d\n", error); - return error; - } - return error; } @@ -1182,6 +1173,7 @@ MODULE_DEVICE_TABLE(i2c, rohm_bu21023_i2c_id); static struct i2c_driver rohm_bu21023_i2c_driver = { .driver = { .name = BU21023_NAME, + .dev_groups = rohm_ts_groups, }, .probe = rohm_bu21023_i2c_probe, .id_table = rohm_bu21023_i2c_id, -- GitLab From 2ad952810861faac2cda65189c7e96c802c7a8f2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:28 -0700 Subject: [PATCH 0024/1451] Input: s6sy761 - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Reviewed-by: Andi Shyti Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-19-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/s6sy761.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/input/touchscreen/s6sy761.c b/drivers/input/touchscreen/s6sy761.c index 998d99d189111..149cc2c4925e9 100644 --- a/drivers/input/touchscreen/s6sy761.c +++ b/drivers/input/touchscreen/s6sy761.c @@ -286,10 +286,7 @@ static struct attribute *s6sy761_sysfs_attrs[] = { &dev_attr_devid.attr, NULL }; - -static struct attribute_group s6sy761_attribute_group = { - .attrs = s6sy761_sysfs_attrs -}; +ATTRIBUTE_GROUPS(s6sy761_sysfs); static int s6sy761_power_on(struct s6sy761_data *sdata) { @@ -465,10 +462,6 @@ static int s6sy761_probe(struct i2c_client *client) if (err) return err; - err = devm_device_add_group(&client->dev, &s6sy761_attribute_group); - if (err) - return err; - pm_runtime_enable(&client->dev); return 0; @@ -535,6 +528,7 @@ MODULE_DEVICE_TABLE(i2c, s6sy761_id); static struct i2c_driver s6sy761_driver = { .driver = { .name = S6SY761_DEV_NAME, + .dev_groups = s6sy761_sysfs_groups, .of_match_table = of_match_ptr(s6sy761_of_match), .pm = pm_ptr(&s6sy761_pm_ops), }, -- GitLab From 6cc3ecfded342cb56a8ebf5de3541b2d9cc41017 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:29 -0700 Subject: [PATCH 0025/1451] Input: stmfts - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Reviewed-by: Andi Shyti Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-20-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/stmfts.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c index 56e371fd88fa1..85010fa079082 100644 --- a/drivers/input/touchscreen/stmfts.c +++ b/drivers/input/touchscreen/stmfts.c @@ -517,10 +517,7 @@ static struct attribute *stmfts_sysfs_attrs[] = { &dev_attr_hover_enable.attr, NULL }; - -static struct attribute_group stmfts_attribute_group = { - .attrs = stmfts_sysfs_attrs -}; +ATTRIBUTE_GROUPS(stmfts_sysfs); static int stmfts_power_on(struct stmfts_data *sdata) { @@ -727,10 +724,6 @@ static int stmfts_probe(struct i2c_client *client) } } - err = devm_device_add_group(&client->dev, &stmfts_attribute_group); - if (err) - return err; - pm_runtime_enable(&client->dev); device_enable_async_suspend(&client->dev); @@ -804,6 +797,7 @@ MODULE_DEVICE_TABLE(i2c, stmfts_id); static struct i2c_driver stmfts_driver = { .driver = { .name = STMFTS_DEV_NAME, + .dev_groups = stmfts_sysfs_groups, .of_match_table = of_match_ptr(stmfts_of_match), .pm = pm_ptr(&stmfts_pm_ops), .probe_type = PROBE_PREFER_ASYNCHRONOUS, -- GitLab From 97f2bedb620c17c41fee2a7758dddbfcbaa0812b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:30 -0700 Subject: [PATCH 0026/1451] Input: tsc2004/5 - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with sysfs_create_group() have device core do this by setting up dev_groups pointer in the driver structure. Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-21-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2004.c | 7 ++++--- drivers/input/touchscreen/tsc2005.c | 7 ++++--- drivers/input/touchscreen/tsc200x-core.c | 18 +++++++----------- drivers/input/touchscreen/tsc200x-core.h | 1 + 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/input/touchscreen/tsc2004.c b/drivers/input/touchscreen/tsc2004.c index b5e904c5b7c49..89c5248f66f6f 100644 --- a/drivers/input/touchscreen/tsc2004.c +++ b/drivers/input/touchscreen/tsc2004.c @@ -63,9 +63,10 @@ MODULE_DEVICE_TABLE(of, tsc2004_of_match); static struct i2c_driver tsc2004_driver = { .driver = { - .name = "tsc2004", - .of_match_table = of_match_ptr(tsc2004_of_match), - .pm = pm_sleep_ptr(&tsc200x_pm_ops), + .name = "tsc2004", + .dev_groups = tsc200x_groups, + .of_match_table = of_match_ptr(tsc2004_of_match), + .pm = pm_sleep_ptr(&tsc200x_pm_ops), }, .id_table = tsc2004_idtable, .probe = tsc2004_probe, diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index b6dfbcfc8c19b..1b40ce0ca1b99 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -79,9 +79,10 @@ MODULE_DEVICE_TABLE(of, tsc2005_of_match); static struct spi_driver tsc2005_driver = { .driver = { - .name = "tsc2005", - .of_match_table = of_match_ptr(tsc2005_of_match), - .pm = pm_sleep_ptr(&tsc200x_pm_ops), + .name = "tsc2005", + .dev_groups = tsc200x_groups, + .of_match_table = of_match_ptr(tsc2005_of_match), + .pm = pm_sleep_ptr(&tsc200x_pm_ops), }, .probe = tsc2005_probe, .remove = tsc2005_remove, diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c index b799f26fcf8fa..a4c0e9db9bb94 100644 --- a/drivers/input/touchscreen/tsc200x-core.c +++ b/drivers/input/touchscreen/tsc200x-core.c @@ -356,6 +356,12 @@ static const struct attribute_group tsc200x_attr_group = { .attrs = tsc200x_attrs, }; +const struct attribute_group *tsc200x_groups[] = { + &tsc200x_attr_group, + NULL +}; +EXPORT_SYMBOL_GPL(tsc200x_groups); + static void tsc200x_esd_work(struct work_struct *work) { struct tsc200x *ts = container_of(work, struct tsc200x, esd_work.work); @@ -553,25 +559,17 @@ int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id, return error; dev_set_drvdata(dev, ts); - error = sysfs_create_group(&dev->kobj, &tsc200x_attr_group); - if (error) { - dev_err(dev, - "Failed to create sysfs attributes, err: %d\n", error); - goto disable_regulator; - } error = input_register_device(ts->idev); if (error) { dev_err(dev, "Failed to register input device, err: %d\n", error); - goto err_remove_sysfs; + goto disable_regulator; } irq_set_irq_wake(irq, 1); return 0; -err_remove_sysfs: - sysfs_remove_group(&dev->kobj, &tsc200x_attr_group); disable_regulator: regulator_disable(ts->vio); return error; @@ -582,8 +580,6 @@ void tsc200x_remove(struct device *dev) { struct tsc200x *ts = dev_get_drvdata(dev); - sysfs_remove_group(&dev->kobj, &tsc200x_attr_group); - regulator_disable(ts->vio); } EXPORT_SYMBOL_GPL(tsc200x_remove); diff --git a/drivers/input/touchscreen/tsc200x-core.h b/drivers/input/touchscreen/tsc200x-core.h index 4ded34425b21e..37de91efd78ea 100644 --- a/drivers/input/touchscreen/tsc200x-core.h +++ b/drivers/input/touchscreen/tsc200x-core.h @@ -70,6 +70,7 @@ extern const struct regmap_config tsc200x_regmap_config; extern const struct dev_pm_ops tsc200x_pm_ops; +extern const struct attribute_group *tsc200x_groups[]; int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id, struct regmap *regmap, -- GitLab From 305dd76455038f3b2338bd0560387cf829c7567c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 28 Jul 2023 17:51:31 -0700 Subject: [PATCH 0027/1451] Input: wdt87xx_i2c - use device core to create driver-specific device attributes Instead of creating driver-specific device attributes with devm_device_add_group() have device core do this by setting up dev_groups pointer in the driver structure. Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20230729005133.1095051-22-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wdt87xx_i2c.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c index cbc4750c53f9a..128341a6696bc 100644 --- a/drivers/input/touchscreen/wdt87xx_i2c.c +++ b/drivers/input/touchscreen/wdt87xx_i2c.c @@ -944,10 +944,7 @@ static struct attribute *wdt87xx_attrs[] = { &dev_attr_update_fw.attr, NULL }; - -static const struct attribute_group wdt87xx_attr_group = { - .attrs = wdt87xx_attrs, -}; +ATTRIBUTE_GROUPS(wdt87xx); static void wdt87xx_report_contact(struct input_dev *input, struct wdt87xx_sys_param *param, @@ -1104,12 +1101,6 @@ static int wdt87xx_ts_probe(struct i2c_client *client) return error; } - error = devm_device_add_group(&client->dev, &wdt87xx_attr_group); - if (error) { - dev_err(&client->dev, "create sysfs failed: %d\n", error); - return error; - } - return 0; } @@ -1172,8 +1163,9 @@ static struct i2c_driver wdt87xx_driver = { .probe = wdt87xx_ts_probe, .id_table = wdt87xx_dev_id, .driver = { - .name = WDT87XX_NAME, - .pm = pm_sleep_ptr(&wdt87xx_pm_ops), + .name = WDT87XX_NAME, + .dev_groups = wdt87xx_groups, + .pm = pm_sleep_ptr(&wdt87xx_pm_ops), .acpi_match_table = ACPI_PTR(wdt87xx_acpi_id), }, }; -- GitLab From 99f998733dac8b84b96981bf170d39ec721d5b97 Mon Sep 17 00:00:00 2001 From: Chen Jiahao Date: Thu, 17 Aug 2023 16:33:36 +0800 Subject: [PATCH 0028/1451] remoteproc: stm32: Clean up redundant dev_err_probe() Referring to platform_get_irq()'s definition, the return value has already been checked if ret < 0, and printed via dev_err_probe(). Calling dev_err_probe() one more time outside platform_get_irq() is obviously redundant. Removing outside dev_err_probe() to clean it up. Besides, switch to use platform_get_irq_optional() since the irq is optional here. Signed-off-by: Chen Jiahao Acked-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20230817083336.404635-1-chenjiahao16@huawei.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/stm32_rproc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c index 9d9b13530f78a..4f469f0bcf8b2 100644 --- a/drivers/remoteproc/stm32_rproc.c +++ b/drivers/remoteproc/stm32_rproc.c @@ -712,9 +712,9 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev, unsigned int tzen; int err, irq; - irq = platform_get_irq(pdev, 0); + irq = platform_get_irq_optional(pdev, 0); if (irq == -EPROBE_DEFER) - return dev_err_probe(dev, irq, "failed to get interrupt\n"); + return irq; if (irq > 0) { err = devm_request_irq(dev, irq, stm32_rproc_wdg, 0, -- GitLab From cdd2218700c129ea24b778856d7819884446999a Mon Sep 17 00:00:00 2001 From: Tinghan Shen Date: Fri, 1 Sep 2023 16:09:22 +0800 Subject: [PATCH 0029/1451] dt-bindings: remoteproc: mediatek: Improve the rpmsg subnode definition Improve the definition of the rpmsg subnode by assigning a distinct node name and adding the definition source of node properties. Signed-off-by: Tinghan Shen Acked-by: Rob Herring Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230901080935.14571-2-tinghan.shen@mediatek.com Signed-off-by: Mathieu Poirier --- .../bindings/remoteproc/mtk,scp.yaml | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml b/Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml index 895415772d1d6..271081df0e46a 100644 --- a/Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml +++ b/Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml @@ -58,6 +58,18 @@ properties: memory-region: maxItems: 1 + cros-ec-rpmsg: + $ref: /schemas/mfd/google,cros-ec.yaml + description: + This subnode represents the rpmsg device. The properties + of this node are defined by the individual bindings for + the rpmsg devices. + + required: + - mediatek,rpmsg-name + + unevaluatedProperties: false + required: - compatible - reg @@ -89,21 +101,7 @@ allOf: reg-names: maxItems: 2 -additionalProperties: - type: object - description: - Subnodes of the SCP represent rpmsg devices. The names of the devices - are not important. The properties of these nodes are defined by the - individual bindings for the rpmsg devices. - properties: - mediatek,rpmsg-name: - $ref: /schemas/types.yaml#/definitions/string-array - description: - Contains the name for the rpmsg device. Used to match - the subnode to rpmsg device announced by SCP. - - required: - - mediatek,rpmsg-name +additionalProperties: false examples: - | @@ -118,7 +116,8 @@ examples: clocks = <&infracfg CLK_INFRA_SCPSYS>; clock-names = "main"; - cros_ec { + cros-ec-rpmsg { + compatible = "google,cros-ec-rpmsg"; mediatek,rpmsg-name = "cros-ec-rpmsg"; }; }; -- GitLab From 6b55b1e2fd7f0a91e75271c6199a81e72a403492 Mon Sep 17 00:00:00 2001 From: Tinghan Shen Date: Fri, 1 Sep 2023 16:09:24 +0800 Subject: [PATCH 0030/1451] dt-bindings: remoteproc: mediatek: Support MT8195 dual-core SCP Extend the SCP binding to describe the MT8195 dual-core SCP. Under different applications, the MT8195 SCP can be used as single-core or dual-core. This change keeps the single-core definitions and adds new definitions for the dual-core use case. Signed-off-by: Tinghan Shen Reviewed-by: Rob Herring Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230901080935.14571-4-tinghan.shen@mediatek.com Signed-off-by: Mathieu Poirier --- .../bindings/remoteproc/mtk,scp.yaml | 145 +++++++++++++++++- 1 file changed, 141 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml b/Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml index 271081df0e46a..09102dda4942c 100644 --- a/Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml +++ b/Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml @@ -21,6 +21,7 @@ properties: - mediatek,mt8188-scp - mediatek,mt8192-scp - mediatek,mt8195-scp + - mediatek,mt8195-scp-dual reg: description: @@ -31,10 +32,7 @@ properties: reg-names: minItems: 2 - items: - - const: sram - - const: cfg - - const: l1tcm + maxItems: 3 clocks: description: @@ -70,6 +68,81 @@ properties: unevaluatedProperties: false + '#address-cells': + const: 1 + + '#size-cells': + const: 1 + + ranges: + description: + Standard ranges definition providing address translations for + local SCP SRAM address spaces to bus addresses. + +patternProperties: + "^scp@[a-f0-9]+$": + type: object + description: + The MediaTek SCP integrated to SoC might be a multi-core version. + The other cores are represented as child nodes of the boot core. + There are some integration differences for the IP like the usage of + address translator for translating SoC bus addresses into address space + for the processor. + + Each SCP core has own cache memory. The SRAM and L1TCM are shared by + cores. The power of cache, SRAM and L1TCM power should be enabled + before booting SCP cores. The size of cache, SRAM, and L1TCM are varied + on differnt SoCs. + + The SCP cores do not use an MMU, but has a set of registers to + control the translations between 32-bit CPU addresses into system bus + addresses. Cache and memory access settings are provided through a + Memory Protection Unit (MPU), programmable only from the SCP. + + properties: + compatible: + enum: + - mediatek,scp-core + + reg: + description: The base address and size of SRAM. + maxItems: 1 + + reg-names: + const: sram + + interrupts: + maxItems: 1 + + firmware-name: + $ref: /schemas/types.yaml#/definitions/string + description: + If present, name (or relative path) of the file within the + firmware search path containing the firmware image used when + initializing sub cores of multi-core SCP. + + memory-region: + maxItems: 1 + + cros-ec-rpmsg: + $ref: /schemas/mfd/google,cros-ec.yaml + description: + This subnode represents the rpmsg device. The properties + of this node are defined by the individual bindings for + the rpmsg devices. + + required: + - mediatek,rpmsg-name + + unevaluatedProperties: false + + required: + - compatible + - reg + - reg-names + + additionalProperties: false + required: - compatible - reg @@ -99,7 +172,37 @@ allOf: reg: maxItems: 2 reg-names: + items: + - const: sram + - const: cfg + - if: + properties: + compatible: + enum: + - mediatek,mt8192-scp + - mediatek,mt8195-scp + then: + properties: + reg: + maxItems: 3 + reg-names: + items: + - const: sram + - const: cfg + - const: l1tcm + - if: + properties: + compatible: + enum: + - mediatek,mt8195-scp-dual + then: + properties: + reg: maxItems: 2 + reg-names: + items: + - const: cfg + - const: l1tcm additionalProperties: false @@ -121,3 +224,37 @@ examples: mediatek,rpmsg-name = "cros-ec-rpmsg"; }; }; + + - | + scp@10500000 { + compatible = "mediatek,mt8195-scp-dual"; + reg = <0x10720000 0xe0000>, + <0x10700000 0x8000>; + reg-names = "cfg", "l1tcm"; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x10500000 0x100000>; + + scp@0 { + compatible = "mediatek,scp-core"; + reg = <0x0 0xa0000>; + reg-names = "sram"; + + cros-ec-rpmsg { + compatible = "google,cros-ec-rpmsg"; + mediatek,rpmsg-name = "cros-ec-rpmsg"; + }; + }; + + scp@a0000 { + compatible = "mediatek,scp-core"; + reg = <0xa0000 0x20000>; + reg-names = "sram"; + + cros-ec-rpmsg { + compatible = "google,cros-ec-rpmsg"; + mediatek,rpmsg-name = "cros-ec-rpmsg"; + }; + }; + }; -- GitLab From 6a1c9aaf04eb4536da922f18e05c73a2afadfe2a Mon Sep 17 00:00:00 2001 From: Tinghan Shen Date: Fri, 1 Sep 2023 16:09:25 +0800 Subject: [PATCH 0031/1451] remoteproc: mediatek: Add MT8195 SCP core 1 operations The SCP rproc driver has a set of chip dependent callbacks for boot sequence and IRQ handling. Implement these callbacks for MT8195 SCP core 1. Signed-off-by: Tinghan Shen Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Matthias Brugger Tested-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230901080935.14571-5-tinghan.shen@mediatek.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/mtk_common.h | 9 ++++++ drivers/remoteproc/mtk_scp.c | 55 +++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/drivers/remoteproc/mtk_common.h b/drivers/remoteproc/mtk_common.h index ea6fa1100a00b..c0905aec3b4bc 100644 --- a/drivers/remoteproc/mtk_common.h +++ b/drivers/remoteproc/mtk_common.h @@ -47,6 +47,7 @@ #define MT8192_SCP2SPM_IPC_CLR 0x4094 #define MT8192_GIPC_IN_SET 0x4098 #define MT8192_HOST_IPC_INT_BIT BIT(0) +#define MT8195_CORE1_HOST_IPC_INT_BIT BIT(4) #define MT8192_CORE0_SW_RSTN_CLR 0x10000 #define MT8192_CORE0_SW_RSTN_SET 0x10004 @@ -56,6 +57,14 @@ #define MT8195_L1TCM_SRAM_PDN_RESERVED_RSI_BITS GENMASK(7, 4) +#define MT8195_CPU1_SRAM_PD 0x1084 +#define MT8195_SSHUB2APMCU_IPC_SET 0x4088 +#define MT8195_SSHUB2APMCU_IPC_CLR 0x408C +#define MT8195_CORE1_SW_RSTN_CLR 0x20000 +#define MT8195_CORE1_SW_RSTN_SET 0x20004 +#define MT8195_CORE1_MEM_ATT_PREDEF 0x20008 +#define MT8195_CORE1_WDT_CFG 0x20034 + #define SCP_FW_VER_LEN 32 #define SCP_SHARE_BUFFER_SIZE 288 diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index dcc94ee2458d8..48e759c2d4869 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -176,6 +176,16 @@ static void mt8192_scp_reset_deassert(struct mtk_scp *scp) writel(1, scp->reg_base + MT8192_CORE0_SW_RSTN_CLR); } +static void mt8195_scp_c1_reset_assert(struct mtk_scp *scp) +{ + writel(1, scp->reg_base + MT8195_CORE1_SW_RSTN_SET); +} + +static void mt8195_scp_c1_reset_deassert(struct mtk_scp *scp) +{ + writel(1, scp->reg_base + MT8195_CORE1_SW_RSTN_CLR); +} + static void mt8183_scp_irq_handler(struct mtk_scp *scp) { u32 scp_to_host; @@ -212,6 +222,18 @@ static void mt8192_scp_irq_handler(struct mtk_scp *scp) } } +static void mt8195_scp_c1_irq_handler(struct mtk_scp *scp) +{ + u32 scp_to_host; + + scp_to_host = readl(scp->reg_base + MT8195_SSHUB2APMCU_IPC_SET); + + if (scp_to_host & MT8192_SCP_IPC_INT_BIT) + scp_ipi_handler(scp); + + writel(scp_to_host, scp->reg_base + MT8195_SSHUB2APMCU_IPC_CLR); +} + static irqreturn_t scp_irq_handler(int irq, void *priv) { struct mtk_scp *scp = priv; @@ -453,6 +475,18 @@ static int mt8195_scp_before_load(struct mtk_scp *scp) return 0; } +static int mt8195_scp_c1_before_load(struct mtk_scp *scp) +{ + scp->data->scp_reset_assert(scp); + + scp_sram_power_on(scp->reg_base + MT8195_CPU1_SRAM_PD, 0); + + /* enable MPU for all memory regions */ + writel(0xff, scp->reg_base + MT8195_CORE1_MEM_ATT_PREDEF); + + return 0; +} + static int scp_load(struct rproc *rproc, const struct firmware *fw) { struct mtk_scp *scp = rproc->priv; @@ -625,6 +659,15 @@ static void mt8195_scp_stop(struct mtk_scp *scp) writel(0, scp->reg_base + MT8192_CORE0_WDT_CFG); } +static void mt8195_scp_c1_stop(struct mtk_scp *scp) +{ + /* Power off CPU SRAM */ + scp_sram_power_off(scp->reg_base + MT8195_CPU1_SRAM_PD, 0); + + /* Disable SCP watchdog */ + writel(0, scp->reg_base + MT8195_CORE1_WDT_CFG); +} + static int scp_stop(struct rproc *rproc) { struct mtk_scp *scp = rproc->priv; @@ -989,6 +1032,18 @@ static const struct mtk_scp_of_data mt8195_of_data = { .host_to_scp_int_bit = MT8192_HOST_IPC_INT_BIT, }; +static const struct mtk_scp_of_data mt8195_of_data_c1 = { + .scp_clk_get = mt8195_scp_clk_get, + .scp_before_load = mt8195_scp_c1_before_load, + .scp_irq_handler = mt8195_scp_c1_irq_handler, + .scp_reset_assert = mt8195_scp_c1_reset_assert, + .scp_reset_deassert = mt8195_scp_c1_reset_deassert, + .scp_stop = mt8195_scp_c1_stop, + .scp_da_to_va = mt8192_scp_da_to_va, + .host_to_scp_reg = MT8192_GIPC_IN_SET, + .host_to_scp_int_bit = MT8195_CORE1_HOST_IPC_INT_BIT, +}; + static const struct of_device_id mtk_scp_of_match[] = { { .compatible = "mediatek,mt8183-scp", .data = &mt8183_of_data }, { .compatible = "mediatek,mt8186-scp", .data = &mt8186_of_data }, -- GitLab From 9ea166698f48c299ca6bd4730950ca1176f51e1b Mon Sep 17 00:00:00 2001 From: Tinghan Shen Date: Fri, 1 Sep 2023 16:09:26 +0800 Subject: [PATCH 0032/1451] remoteproc: mediatek: Extract SCP common registers This is the 1st preliminary steps for probing multi-core SCP. The registers of config and l1tcm are common on single-core SCP and multi-core SCP. Extract these registers out to reduce duplicated fields in mtk_scp when multiple SCP instances are created. Signed-off-by: Tinghan Shen Reviewed-by: AngeloGioacchino Del Regno Tested-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230901080935.14571-6-tinghan.shen@mediatek.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/mtk_common.h | 13 ++- drivers/remoteproc/mtk_scp.c | 164 ++++++++++++++++--------------- drivers/remoteproc/mtk_scp_ipi.c | 4 +- 3 files changed, 96 insertions(+), 85 deletions(-) diff --git a/drivers/remoteproc/mtk_common.h b/drivers/remoteproc/mtk_common.h index c0905aec3b4bc..b04d71277c1f3 100644 --- a/drivers/remoteproc/mtk_common.h +++ b/drivers/remoteproc/mtk_common.h @@ -100,17 +100,20 @@ struct mtk_scp_of_data { size_t ipi_buf_offset; }; +struct mtk_scp_of_cluster { + void __iomem *reg_base; + void __iomem *l1tcm_base; + size_t l1tcm_size; + phys_addr_t l1tcm_phys; +}; + struct mtk_scp { struct device *dev; struct rproc *rproc; struct clk *clk; - void __iomem *reg_base; void __iomem *sram_base; size_t sram_size; phys_addr_t sram_phys; - void __iomem *l1tcm_base; - size_t l1tcm_size; - phys_addr_t l1tcm_phys; const struct mtk_scp_of_data *data; @@ -128,6 +131,8 @@ struct mtk_scp { size_t dram_size; struct rproc_subdev *rpmsg_subdev; + + struct mtk_scp_of_cluster *cluster; }; /** diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index 48e759c2d4869..f88e60e4bc212 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -152,45 +152,45 @@ static void mt8183_scp_reset_assert(struct mtk_scp *scp) { u32 val; - val = readl(scp->reg_base + MT8183_SW_RSTN); + val = readl(scp->cluster->reg_base + MT8183_SW_RSTN); val &= ~MT8183_SW_RSTN_BIT; - writel(val, scp->reg_base + MT8183_SW_RSTN); + writel(val, scp->cluster->reg_base + MT8183_SW_RSTN); } static void mt8183_scp_reset_deassert(struct mtk_scp *scp) { u32 val; - val = readl(scp->reg_base + MT8183_SW_RSTN); + val = readl(scp->cluster->reg_base + MT8183_SW_RSTN); val |= MT8183_SW_RSTN_BIT; - writel(val, scp->reg_base + MT8183_SW_RSTN); + writel(val, scp->cluster->reg_base + MT8183_SW_RSTN); } static void mt8192_scp_reset_assert(struct mtk_scp *scp) { - writel(1, scp->reg_base + MT8192_CORE0_SW_RSTN_SET); + writel(1, scp->cluster->reg_base + MT8192_CORE0_SW_RSTN_SET); } static void mt8192_scp_reset_deassert(struct mtk_scp *scp) { - writel(1, scp->reg_base + MT8192_CORE0_SW_RSTN_CLR); + writel(1, scp->cluster->reg_base + MT8192_CORE0_SW_RSTN_CLR); } static void mt8195_scp_c1_reset_assert(struct mtk_scp *scp) { - writel(1, scp->reg_base + MT8195_CORE1_SW_RSTN_SET); + writel(1, scp->cluster->reg_base + MT8195_CORE1_SW_RSTN_SET); } static void mt8195_scp_c1_reset_deassert(struct mtk_scp *scp) { - writel(1, scp->reg_base + MT8195_CORE1_SW_RSTN_CLR); + writel(1, scp->cluster->reg_base + MT8195_CORE1_SW_RSTN_CLR); } static void mt8183_scp_irq_handler(struct mtk_scp *scp) { u32 scp_to_host; - scp_to_host = readl(scp->reg_base + MT8183_SCP_TO_HOST); + scp_to_host = readl(scp->cluster->reg_base + MT8183_SCP_TO_HOST); if (scp_to_host & MT8183_SCP_IPC_INT_BIT) scp_ipi_handler(scp); else @@ -198,14 +198,14 @@ static void mt8183_scp_irq_handler(struct mtk_scp *scp) /* SCP won't send another interrupt until we set SCP_TO_HOST to 0. */ writel(MT8183_SCP_IPC_INT_BIT | MT8183_SCP_WDT_INT_BIT, - scp->reg_base + MT8183_SCP_TO_HOST); + scp->cluster->reg_base + MT8183_SCP_TO_HOST); } static void mt8192_scp_irq_handler(struct mtk_scp *scp) { u32 scp_to_host; - scp_to_host = readl(scp->reg_base + MT8192_SCP2APMCU_IPC_SET); + scp_to_host = readl(scp->cluster->reg_base + MT8192_SCP2APMCU_IPC_SET); if (scp_to_host & MT8192_SCP_IPC_INT_BIT) { scp_ipi_handler(scp); @@ -215,10 +215,10 @@ static void mt8192_scp_irq_handler(struct mtk_scp *scp) * MT8192_SCP2APMCU_IPC. */ writel(MT8192_SCP_IPC_INT_BIT, - scp->reg_base + MT8192_SCP2APMCU_IPC_CLR); + scp->cluster->reg_base + MT8192_SCP2APMCU_IPC_CLR); } else { scp_wdt_handler(scp, scp_to_host); - writel(1, scp->reg_base + MT8192_CORE0_WDT_IRQ); + writel(1, scp->cluster->reg_base + MT8192_CORE0_WDT_IRQ); } } @@ -226,12 +226,12 @@ static void mt8195_scp_c1_irq_handler(struct mtk_scp *scp) { u32 scp_to_host; - scp_to_host = readl(scp->reg_base + MT8195_SSHUB2APMCU_IPC_SET); + scp_to_host = readl(scp->cluster->reg_base + MT8195_SSHUB2APMCU_IPC_SET); if (scp_to_host & MT8192_SCP_IPC_INT_BIT) scp_ipi_handler(scp); - writel(scp_to_host, scp->reg_base + MT8195_SSHUB2APMCU_IPC_CLR); + writel(scp_to_host, scp->cluster->reg_base + MT8195_SSHUB2APMCU_IPC_CLR); } static irqreturn_t scp_irq_handler(int irq, void *priv) @@ -363,26 +363,26 @@ static int mt8195_scp_clk_get(struct mtk_scp *scp) static int mt8183_scp_before_load(struct mtk_scp *scp) { /* Clear SCP to host interrupt */ - writel(MT8183_SCP_IPC_INT_BIT, scp->reg_base + MT8183_SCP_TO_HOST); + writel(MT8183_SCP_IPC_INT_BIT, scp->cluster->reg_base + MT8183_SCP_TO_HOST); /* Reset clocks before loading FW */ - writel(0x0, scp->reg_base + MT8183_SCP_CLK_SW_SEL); - writel(0x0, scp->reg_base + MT8183_SCP_CLK_DIV_SEL); + writel(0x0, scp->cluster->reg_base + MT8183_SCP_CLK_SW_SEL); + writel(0x0, scp->cluster->reg_base + MT8183_SCP_CLK_DIV_SEL); /* Initialize TCM before loading FW. */ - writel(0x0, scp->reg_base + MT8183_SCP_L1_SRAM_PD); - writel(0x0, scp->reg_base + MT8183_SCP_TCM_TAIL_SRAM_PD); + writel(0x0, scp->cluster->reg_base + MT8183_SCP_L1_SRAM_PD); + writel(0x0, scp->cluster->reg_base + MT8183_SCP_TCM_TAIL_SRAM_PD); /* Turn on the power of SCP's SRAM before using it. */ - writel(0x0, scp->reg_base + MT8183_SCP_SRAM_PDN); + writel(0x0, scp->cluster->reg_base + MT8183_SCP_SRAM_PDN); /* * Set I-cache and D-cache size before loading SCP FW. * SCP SRAM logical address may change when cache size setting differs. */ writel(MT8183_SCP_CACHE_CON_WAYEN | MT8183_SCP_CACHESIZE_8KB, - scp->reg_base + MT8183_SCP_CACHE_CON); - writel(MT8183_SCP_CACHESIZE_8KB, scp->reg_base + MT8183_SCP_DCACHE_CON); + scp->cluster->reg_base + MT8183_SCP_CACHE_CON); + writel(MT8183_SCP_CACHESIZE_8KB, scp->cluster->reg_base + MT8183_SCP_DCACHE_CON); return 0; } @@ -408,28 +408,28 @@ static void scp_sram_power_off(void __iomem *addr, u32 reserved_mask) static int mt8186_scp_before_load(struct mtk_scp *scp) { /* Clear SCP to host interrupt */ - writel(MT8183_SCP_IPC_INT_BIT, scp->reg_base + MT8183_SCP_TO_HOST); + writel(MT8183_SCP_IPC_INT_BIT, scp->cluster->reg_base + MT8183_SCP_TO_HOST); /* Reset clocks before loading FW */ - writel(0x0, scp->reg_base + MT8183_SCP_CLK_SW_SEL); - writel(0x0, scp->reg_base + MT8183_SCP_CLK_DIV_SEL); + writel(0x0, scp->cluster->reg_base + MT8183_SCP_CLK_SW_SEL); + writel(0x0, scp->cluster->reg_base + MT8183_SCP_CLK_DIV_SEL); /* Turn on the power of SCP's SRAM before using it. Enable 1 block per time*/ - scp_sram_power_on(scp->reg_base + MT8183_SCP_SRAM_PDN, 0); + scp_sram_power_on(scp->cluster->reg_base + MT8183_SCP_SRAM_PDN, 0); /* Initialize TCM before loading FW. */ - writel(0x0, scp->reg_base + MT8183_SCP_L1_SRAM_PD); - writel(0x0, scp->reg_base + MT8183_SCP_TCM_TAIL_SRAM_PD); - writel(0x0, scp->reg_base + MT8186_SCP_L1_SRAM_PD_P1); - writel(0x0, scp->reg_base + MT8186_SCP_L1_SRAM_PD_p2); + writel(0x0, scp->cluster->reg_base + MT8183_SCP_L1_SRAM_PD); + writel(0x0, scp->cluster->reg_base + MT8183_SCP_TCM_TAIL_SRAM_PD); + writel(0x0, scp->cluster->reg_base + MT8186_SCP_L1_SRAM_PD_P1); + writel(0x0, scp->cluster->reg_base + MT8186_SCP_L1_SRAM_PD_p2); /* * Set I-cache and D-cache size before loading SCP FW. * SCP SRAM logical address may change when cache size setting differs. */ writel(MT8183_SCP_CACHE_CON_WAYEN | MT8183_SCP_CACHESIZE_8KB, - scp->reg_base + MT8183_SCP_CACHE_CON); - writel(MT8183_SCP_CACHESIZE_8KB, scp->reg_base + MT8183_SCP_DCACHE_CON); + scp->cluster->reg_base + MT8183_SCP_CACHE_CON); + writel(MT8183_SCP_CACHESIZE_8KB, scp->cluster->reg_base + MT8183_SCP_DCACHE_CON); return 0; } @@ -437,19 +437,19 @@ static int mt8186_scp_before_load(struct mtk_scp *scp) static int mt8192_scp_before_load(struct mtk_scp *scp) { /* clear SPM interrupt, SCP2SPM_IPC_CLR */ - writel(0xff, scp->reg_base + MT8192_SCP2SPM_IPC_CLR); + writel(0xff, scp->cluster->reg_base + MT8192_SCP2SPM_IPC_CLR); - writel(1, scp->reg_base + MT8192_CORE0_SW_RSTN_SET); + writel(1, scp->cluster->reg_base + MT8192_CORE0_SW_RSTN_SET); /* enable SRAM clock */ - scp_sram_power_on(scp->reg_base + MT8192_L2TCM_SRAM_PD_0, 0); - scp_sram_power_on(scp->reg_base + MT8192_L2TCM_SRAM_PD_1, 0); - scp_sram_power_on(scp->reg_base + MT8192_L2TCM_SRAM_PD_2, 0); - scp_sram_power_on(scp->reg_base + MT8192_L1TCM_SRAM_PDN, 0); - scp_sram_power_on(scp->reg_base + MT8192_CPU0_SRAM_PD, 0); + scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_0, 0); + scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_1, 0); + scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_2, 0); + scp_sram_power_on(scp->cluster->reg_base + MT8192_L1TCM_SRAM_PDN, 0); + scp_sram_power_on(scp->cluster->reg_base + MT8192_CPU0_SRAM_PD, 0); /* enable MPU for all memory regions */ - writel(0xff, scp->reg_base + MT8192_CORE0_MEM_ATT_PREDEF); + writel(0xff, scp->cluster->reg_base + MT8192_CORE0_MEM_ATT_PREDEF); return 0; } @@ -457,20 +457,20 @@ static int mt8192_scp_before_load(struct mtk_scp *scp) static int mt8195_scp_before_load(struct mtk_scp *scp) { /* clear SPM interrupt, SCP2SPM_IPC_CLR */ - writel(0xff, scp->reg_base + MT8192_SCP2SPM_IPC_CLR); + writel(0xff, scp->cluster->reg_base + MT8192_SCP2SPM_IPC_CLR); - writel(1, scp->reg_base + MT8192_CORE0_SW_RSTN_SET); + writel(1, scp->cluster->reg_base + MT8192_CORE0_SW_RSTN_SET); /* enable SRAM clock */ - scp_sram_power_on(scp->reg_base + MT8192_L2TCM_SRAM_PD_0, 0); - scp_sram_power_on(scp->reg_base + MT8192_L2TCM_SRAM_PD_1, 0); - scp_sram_power_on(scp->reg_base + MT8192_L2TCM_SRAM_PD_2, 0); - scp_sram_power_on(scp->reg_base + MT8192_L1TCM_SRAM_PDN, + scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_0, 0); + scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_1, 0); + scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_2, 0); + scp_sram_power_on(scp->cluster->reg_base + MT8192_L1TCM_SRAM_PDN, MT8195_L1TCM_SRAM_PDN_RESERVED_RSI_BITS); - scp_sram_power_on(scp->reg_base + MT8192_CPU0_SRAM_PD, 0); + scp_sram_power_on(scp->cluster->reg_base + MT8192_CPU0_SRAM_PD, 0); /* enable MPU for all memory regions */ - writel(0xff, scp->reg_base + MT8192_CORE0_MEM_ATT_PREDEF); + writel(0xff, scp->cluster->reg_base + MT8192_CORE0_MEM_ATT_PREDEF); return 0; } @@ -479,10 +479,10 @@ static int mt8195_scp_c1_before_load(struct mtk_scp *scp) { scp->data->scp_reset_assert(scp); - scp_sram_power_on(scp->reg_base + MT8195_CPU1_SRAM_PD, 0); + scp_sram_power_on(scp->cluster->reg_base + MT8195_CPU1_SRAM_PD, 0); /* enable MPU for all memory regions */ - writel(0xff, scp->reg_base + MT8195_CORE1_MEM_ATT_PREDEF); + writel(0xff, scp->cluster->reg_base + MT8195_CORE1_MEM_ATT_PREDEF); return 0; } @@ -601,11 +601,11 @@ static void *mt8192_scp_da_to_va(struct mtk_scp *scp, u64 da, size_t len) } /* optional memory region */ - if (scp->l1tcm_size && - da >= scp->l1tcm_phys && - (da + len) <= scp->l1tcm_phys + scp->l1tcm_size) { - offset = da - scp->l1tcm_phys; - return (void __force *)scp->l1tcm_base + offset; + if (scp->cluster->l1tcm_size && + da >= scp->cluster->l1tcm_phys && + (da + len) <= scp->cluster->l1tcm_phys + scp->cluster->l1tcm_size) { + offset = da - scp->cluster->l1tcm_phys; + return (void __force *)scp->cluster->l1tcm_base + offset; } /* optional memory region */ @@ -629,43 +629,43 @@ static void *scp_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iome static void mt8183_scp_stop(struct mtk_scp *scp) { /* Disable SCP watchdog */ - writel(0, scp->reg_base + MT8183_WDT_CFG); + writel(0, scp->cluster->reg_base + MT8183_WDT_CFG); } static void mt8192_scp_stop(struct mtk_scp *scp) { /* Disable SRAM clock */ - scp_sram_power_off(scp->reg_base + MT8192_L2TCM_SRAM_PD_0, 0); - scp_sram_power_off(scp->reg_base + MT8192_L2TCM_SRAM_PD_1, 0); - scp_sram_power_off(scp->reg_base + MT8192_L2TCM_SRAM_PD_2, 0); - scp_sram_power_off(scp->reg_base + MT8192_L1TCM_SRAM_PDN, 0); - scp_sram_power_off(scp->reg_base + MT8192_CPU0_SRAM_PD, 0); + scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_0, 0); + scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_1, 0); + scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_2, 0); + scp_sram_power_off(scp->cluster->reg_base + MT8192_L1TCM_SRAM_PDN, 0); + scp_sram_power_off(scp->cluster->reg_base + MT8192_CPU0_SRAM_PD, 0); /* Disable SCP watchdog */ - writel(0, scp->reg_base + MT8192_CORE0_WDT_CFG); + writel(0, scp->cluster->reg_base + MT8192_CORE0_WDT_CFG); } static void mt8195_scp_stop(struct mtk_scp *scp) { /* Disable SRAM clock */ - scp_sram_power_off(scp->reg_base + MT8192_L2TCM_SRAM_PD_0, 0); - scp_sram_power_off(scp->reg_base + MT8192_L2TCM_SRAM_PD_1, 0); - scp_sram_power_off(scp->reg_base + MT8192_L2TCM_SRAM_PD_2, 0); - scp_sram_power_off(scp->reg_base + MT8192_L1TCM_SRAM_PDN, + scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_0, 0); + scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_1, 0); + scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_2, 0); + scp_sram_power_off(scp->cluster->reg_base + MT8192_L1TCM_SRAM_PDN, MT8195_L1TCM_SRAM_PDN_RESERVED_RSI_BITS); - scp_sram_power_off(scp->reg_base + MT8192_CPU0_SRAM_PD, 0); + scp_sram_power_off(scp->cluster->reg_base + MT8192_CPU0_SRAM_PD, 0); /* Disable SCP watchdog */ - writel(0, scp->reg_base + MT8192_CORE0_WDT_CFG); + writel(0, scp->cluster->reg_base + MT8192_CORE0_WDT_CFG); } static void mt8195_scp_c1_stop(struct mtk_scp *scp) { /* Power off CPU SRAM */ - scp_sram_power_off(scp->reg_base + MT8195_CPU1_SRAM_PD, 0); + scp_sram_power_off(scp->cluster->reg_base + MT8195_CPU1_SRAM_PD, 0); /* Disable SCP watchdog */ - writel(0, scp->reg_base + MT8195_CORE1_WDT_CFG); + writel(0, scp->cluster->reg_base + MT8195_CORE1_WDT_CFG); } static int scp_stop(struct rproc *rproc) @@ -859,11 +859,16 @@ static int scp_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct mtk_scp *scp; + struct mtk_scp_of_cluster *scp_cluster; struct rproc *rproc; struct resource *res; const char *fw_name = "scp.img"; int ret, i; + scp_cluster = devm_kzalloc(dev, sizeof(*scp_cluster), GFP_KERNEL); + if (!scp_cluster) + return -ENOMEM; + ret = rproc_of_parse_firmware(dev, 0, &fw_name); if (ret < 0 && ret != -EINVAL) return ret; @@ -876,6 +881,7 @@ static int scp_probe(struct platform_device *pdev) scp->rproc = rproc; scp->dev = dev; scp->data = of_device_get_match_data(dev); + scp->cluster = scp_cluster; platform_set_drvdata(pdev, scp); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); @@ -889,20 +895,20 @@ static int scp_probe(struct platform_device *pdev) /* l1tcm is an optional memory region */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "l1tcm"); - scp->l1tcm_base = devm_ioremap_resource(dev, res); - if (IS_ERR(scp->l1tcm_base)) { - ret = PTR_ERR(scp->l1tcm_base); + scp->cluster->l1tcm_base = devm_ioremap_resource(dev, res); + if (IS_ERR(scp->cluster->l1tcm_base)) { + ret = PTR_ERR(scp->cluster->l1tcm_base); if (ret != -EINVAL) { return dev_err_probe(dev, ret, "Failed to map l1tcm memory\n"); } } else { - scp->l1tcm_size = resource_size(res); - scp->l1tcm_phys = res->start; + scp->cluster->l1tcm_size = resource_size(res); + scp->cluster->l1tcm_phys = res->start; } - scp->reg_base = devm_platform_ioremap_resource_byname(pdev, "cfg"); - if (IS_ERR(scp->reg_base)) - return dev_err_probe(dev, PTR_ERR(scp->reg_base), + scp->cluster->reg_base = devm_platform_ioremap_resource_byname(pdev, "cfg"); + if (IS_ERR(scp->cluster->reg_base)) + return dev_err_probe(dev, PTR_ERR(scp->cluster->reg_base), "Failed to parse and map cfg memory\n"); ret = scp->data->scp_clk_get(scp); diff --git a/drivers/remoteproc/mtk_scp_ipi.c b/drivers/remoteproc/mtk_scp_ipi.c index 9c7c17b9d181f..cd0b60106ec20 100644 --- a/drivers/remoteproc/mtk_scp_ipi.c +++ b/drivers/remoteproc/mtk_scp_ipi.c @@ -177,7 +177,7 @@ int scp_ipi_send(struct mtk_scp *scp, u32 id, void *buf, unsigned int len, mutex_lock(&scp->send_lock); /* Wait until SCP receives the last command */ - ret = readl_poll_timeout_atomic(scp->reg_base + scp->data->host_to_scp_reg, + ret = readl_poll_timeout_atomic(scp->cluster->reg_base + scp->data->host_to_scp_reg, val, !val, 0, SCP_TIMEOUT_US); if (ret) { dev_err(scp->dev, "%s: IPI timeout!\n", __func__); @@ -192,7 +192,7 @@ int scp_ipi_send(struct mtk_scp *scp, u32 id, void *buf, unsigned int len, scp->ipi_id_ack[id] = false; /* send the command to SCP */ writel(scp->data->host_to_scp_int_bit, - scp->reg_base + scp->data->host_to_scp_reg); + scp->cluster->reg_base + scp->data->host_to_scp_reg); if (wait) { /* wait for SCP's ACK */ -- GitLab From fcc14c9cd5ad9186ce9d7777d443e42128ef3b48 Mon Sep 17 00:00:00 2001 From: Tinghan Shen Date: Fri, 1 Sep 2023 16:09:27 +0800 Subject: [PATCH 0033/1451] remoteproc: mediatek: Revise SCP rproc initialization flow for multi-core SCP This is the 2nd preliminary step for probing multi-core SCP. Initialization of configuration and L1TCM registers is extracted to only performed once on multi-core SCP. The rest of remoteproc initialization procedure is similar for both single and multi-core SCP and is applied to each core. Signed-off-by: Tinghan Shen Reviewed-by: AngeloGioacchino Del Regno Tested-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230901080935.14571-7-tinghan.shen@mediatek.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/mtk_scp.c | 63 ++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index f88e60e4bc212..7a2ba1e1e95a6 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -854,21 +854,17 @@ static void scp_remove_rpmsg_subdev(struct mtk_scp *scp) } } -static int scp_probe(struct platform_device *pdev) +static int scp_rproc_init(struct platform_device *pdev, + struct mtk_scp_of_cluster *scp_cluster) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct mtk_scp *scp; - struct mtk_scp_of_cluster *scp_cluster; struct rproc *rproc; struct resource *res; const char *fw_name = "scp.img"; int ret, i; - scp_cluster = devm_kzalloc(dev, sizeof(*scp_cluster), GFP_KERNEL); - if (!scp_cluster) - return -ENOMEM; - ret = rproc_of_parse_firmware(dev, 0, &fw_name); if (ret < 0 && ret != -EINVAL) return ret; @@ -893,24 +889,6 @@ static int scp_probe(struct platform_device *pdev) scp->sram_size = resource_size(res); scp->sram_phys = res->start; - /* l1tcm is an optional memory region */ - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "l1tcm"); - scp->cluster->l1tcm_base = devm_ioremap_resource(dev, res); - if (IS_ERR(scp->cluster->l1tcm_base)) { - ret = PTR_ERR(scp->cluster->l1tcm_base); - if (ret != -EINVAL) { - return dev_err_probe(dev, ret, "Failed to map l1tcm memory\n"); - } - } else { - scp->cluster->l1tcm_size = resource_size(res); - scp->cluster->l1tcm_phys = res->start; - } - - scp->cluster->reg_base = devm_platform_ioremap_resource_byname(pdev, "cfg"); - if (IS_ERR(scp->cluster->reg_base)) - return dev_err_probe(dev, PTR_ERR(scp->cluster->reg_base), - "Failed to parse and map cfg memory\n"); - ret = scp->data->scp_clk_get(scp); if (ret) return ret; @@ -962,6 +940,43 @@ static int scp_probe(struct platform_device *pdev) return ret; } +static int scp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mtk_scp_of_cluster *scp_cluster; + struct resource *res; + int ret; + + scp_cluster = devm_kzalloc(dev, sizeof(*scp_cluster), GFP_KERNEL); + if (!scp_cluster) + return -ENOMEM; + + scp_cluster->reg_base = devm_platform_ioremap_resource_byname(pdev, "cfg"); + if (IS_ERR(scp_cluster->reg_base)) + return dev_err_probe(dev, PTR_ERR(scp_cluster->reg_base), + "Failed to parse and map cfg memory\n"); + + /* l1tcm is an optional memory region */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "l1tcm"); + scp_cluster->l1tcm_base = devm_ioremap_resource(dev, res); + if (IS_ERR(scp_cluster->l1tcm_base)) { + ret = PTR_ERR(scp_cluster->l1tcm_base); + if (ret != -EINVAL) + return dev_err_probe(dev, ret, "Failed to map l1tcm memory\n"); + + scp_cluster->l1tcm_base = NULL; + } else { + scp_cluster->l1tcm_size = resource_size(res); + scp_cluster->l1tcm_phys = res->start; + } + + ret = scp_rproc_init(pdev, scp_cluster); + if (ret) + return ret; + + return 0; +} + static void scp_remove(struct platform_device *pdev) { struct mtk_scp *scp = platform_get_drvdata(pdev); -- GitLab From eaf5b89953b0f88ddc933bd27e120ba4007231ac Mon Sep 17 00:00:00 2001 From: Tinghan Shen Date: Fri, 1 Sep 2023 16:09:28 +0800 Subject: [PATCH 0034/1451] remoteproc: mediatek: Probe SCP cluster on single-core SCP This is the 3rd preliminary step for probing multi-core SCP. Rewrite the probing flow of single-core SCP to adapt with the 'cluster' concept needed by the multi-core SCP. The SCP core object(s) is maintained at the cluster list. Signed-off-by: Tinghan Shen Reviewed-by: AngeloGioacchino Del Regno Tested-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230901080935.14571-8-tinghan.shen@mediatek.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/mtk_common.h | 2 + drivers/remoteproc/mtk_scp.c | 86 +++++++++++++++++++++++---------- 2 files changed, 63 insertions(+), 25 deletions(-) diff --git a/drivers/remoteproc/mtk_common.h b/drivers/remoteproc/mtk_common.h index b04d71277c1f3..1438159ae736b 100644 --- a/drivers/remoteproc/mtk_common.h +++ b/drivers/remoteproc/mtk_common.h @@ -105,6 +105,7 @@ struct mtk_scp_of_cluster { void __iomem *l1tcm_base; size_t l1tcm_size; phys_addr_t l1tcm_phys; + struct list_head mtk_scp_list; }; struct mtk_scp { @@ -132,6 +133,7 @@ struct mtk_scp { struct rproc_subdev *rpmsg_subdev; + struct list_head elem; struct mtk_scp_of_cluster *cluster; }; diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index 7a2ba1e1e95a6..d67dcabdab9e4 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -854,8 +854,8 @@ static void scp_remove_rpmsg_subdev(struct mtk_scp *scp) } } -static int scp_rproc_init(struct platform_device *pdev, - struct mtk_scp_of_cluster *scp_cluster) +static struct mtk_scp *scp_rproc_init(struct platform_device *pdev, + struct mtk_scp_of_cluster *scp_cluster) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; @@ -867,11 +867,13 @@ static int scp_rproc_init(struct platform_device *pdev, ret = rproc_of_parse_firmware(dev, 0, &fw_name); if (ret < 0 && ret != -EINVAL) - return ret; + return ERR_PTR(ret); rproc = devm_rproc_alloc(dev, np->name, &scp_ops, fw_name, sizeof(*scp)); - if (!rproc) - return dev_err_probe(dev, -ENOMEM, "unable to allocate remoteproc\n"); + if (!rproc) { + dev_err(dev, "unable to allocate remoteproc\n"); + return ERR_PTR(-ENOMEM); + } scp = rproc->priv; scp->rproc = rproc; @@ -882,20 +884,21 @@ static int scp_rproc_init(struct platform_device *pdev, res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); scp->sram_base = devm_ioremap_resource(dev, res); - if (IS_ERR(scp->sram_base)) - return dev_err_probe(dev, PTR_ERR(scp->sram_base), - "Failed to parse and map sram memory\n"); + if (IS_ERR(scp->sram_base)) { + dev_err(dev, "Failed to parse and map sram memory\n"); + return ERR_CAST(scp->sram_base); + } scp->sram_size = resource_size(res); scp->sram_phys = res->start; ret = scp->data->scp_clk_get(scp); if (ret) - return ret; + return ERR_PTR(ret); ret = scp_map_memory_region(scp); if (ret) - return ret; + return ERR_PTR(ret); mutex_init(&scp->send_lock); for (i = 0; i < SCP_IPI_MAX; i++) @@ -922,11 +925,7 @@ static int scp_rproc_init(struct platform_device *pdev, goto remove_subdev; } - ret = rproc_add(rproc); - if (ret) - goto remove_subdev; - - return 0; + return scp; remove_subdev: scp_remove_rpmsg_subdev(scp); @@ -937,7 +936,43 @@ static int scp_rproc_init(struct platform_device *pdev, mutex_destroy(&scp->ipi_desc[i].lock); mutex_destroy(&scp->send_lock); - return ret; + return ERR_PTR(ret); +} + +static void scp_free(struct mtk_scp *scp) +{ + int i; + + scp_remove_rpmsg_subdev(scp); + scp_ipi_unregister(scp, SCP_IPI_INIT); + scp_unmap_memory_region(scp); + for (i = 0; i < SCP_IPI_MAX; i++) + mutex_destroy(&scp->ipi_desc[i].lock); + mutex_destroy(&scp->send_lock); +} + +static int scp_cluster_init(struct platform_device *pdev, + struct mtk_scp_of_cluster *scp_cluster) +{ + struct device *dev = &pdev->dev; + struct list_head *scp_list = &scp_cluster->mtk_scp_list; + struct mtk_scp *scp; + int ret; + + scp = scp_rproc_init(pdev, scp_cluster); + if (IS_ERR(scp)) + return PTR_ERR(scp); + + ret = rproc_add(scp->rproc); + if (ret) { + dev_err(dev, "Failed to add rproc\n"); + scp_free(scp); + return ret; + } + + list_add_tail(&scp->elem, scp_list); + + return 0; } static int scp_probe(struct platform_device *pdev) @@ -970,7 +1005,9 @@ static int scp_probe(struct platform_device *pdev) scp_cluster->l1tcm_phys = res->start; } - ret = scp_rproc_init(pdev, scp_cluster); + INIT_LIST_HEAD(&scp_cluster->mtk_scp_list); + + ret = scp_cluster_init(pdev, scp_cluster); if (ret) return ret; @@ -980,15 +1017,14 @@ static int scp_probe(struct platform_device *pdev) static void scp_remove(struct platform_device *pdev) { struct mtk_scp *scp = platform_get_drvdata(pdev); - int i; + struct mtk_scp_of_cluster *scp_cluster = scp->cluster; + struct mtk_scp *temp; - rproc_del(scp->rproc); - scp_remove_rpmsg_subdev(scp); - scp_ipi_unregister(scp, SCP_IPI_INIT); - scp_unmap_memory_region(scp); - for (i = 0; i < SCP_IPI_MAX; i++) - mutex_destroy(&scp->ipi_desc[i].lock); - mutex_destroy(&scp->send_lock); + list_for_each_entry_safe_reverse(scp, temp, &scp_cluster->mtk_scp_list, elem) { + list_del(&scp->elem); + rproc_del(scp->rproc); + scp_free(scp); + } } static const struct mtk_scp_of_data mt8183_of_data = { -- GitLab From 1fdbf0cdde98c113b17f8cd089a892c5f0437d3e Mon Sep 17 00:00:00 2001 From: Tinghan Shen Date: Fri, 1 Sep 2023 16:09:29 +0800 Subject: [PATCH 0035/1451] remoteproc: mediatek: Probe SCP cluster on multi-core SCP The difference of single-core SCP and multi-core SCP device tree is the presence of child device nodes described SCP cores. The SCP driver populates the platform device and checks the child nodes to identify whether it's a single-core SCP or a multi-core SCP. Add the remoteproc instances of multi-core SCP to the SCP cluster list. When the SCP driver is removed, it cleanup resources by walking through the cluster list. Signed-off-by: Tinghan Shen Reviewed-by: AngeloGioacchino Del Regno Tested-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230901080935.14571-9-tinghan.shen@mediatek.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/mtk_scp.c | 124 +++++++++++++++++++++++++++++++++-- 1 file changed, 119 insertions(+), 5 deletions(-) diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index d67dcabdab9e4..4b0e1ae3a4b81 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -855,7 +855,8 @@ static void scp_remove_rpmsg_subdev(struct mtk_scp *scp) } static struct mtk_scp *scp_rproc_init(struct platform_device *pdev, - struct mtk_scp_of_cluster *scp_cluster) + struct mtk_scp_of_cluster *scp_cluster, + const struct mtk_scp_of_data *of_data) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; @@ -878,7 +879,7 @@ static struct mtk_scp *scp_rproc_init(struct platform_device *pdev, scp = rproc->priv; scp->rproc = rproc; scp->dev = dev; - scp->data = of_device_get_match_data(dev); + scp->data = of_data; scp->cluster = scp_cluster; platform_set_drvdata(pdev, scp); @@ -951,15 +952,15 @@ static void scp_free(struct mtk_scp *scp) mutex_destroy(&scp->send_lock); } -static int scp_cluster_init(struct platform_device *pdev, - struct mtk_scp_of_cluster *scp_cluster) +static int scp_add_single_core(struct platform_device *pdev, + struct mtk_scp_of_cluster *scp_cluster) { struct device *dev = &pdev->dev; struct list_head *scp_list = &scp_cluster->mtk_scp_list; struct mtk_scp *scp; int ret; - scp = scp_rproc_init(pdev, scp_cluster); + scp = scp_rproc_init(pdev, scp_cluster, of_device_get_match_data(dev)); if (IS_ERR(scp)) return PTR_ERR(scp); @@ -975,6 +976,108 @@ static int scp_cluster_init(struct platform_device *pdev, return 0; } +static int scp_add_multi_core(struct platform_device *pdev, + struct mtk_scp_of_cluster *scp_cluster) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev_of_node(dev); + struct platform_device *cpdev; + struct device_node *child; + struct list_head *scp_list = &scp_cluster->mtk_scp_list; + const struct mtk_scp_of_data **cluster_of_data; + struct mtk_scp *scp, *temp; + int core_id = 0; + int ret; + + cluster_of_data = (const struct mtk_scp_of_data **)of_device_get_match_data(dev); + + for_each_available_child_of_node(np, child) { + if (!cluster_of_data[core_id]) { + ret = -EINVAL; + dev_err(dev, "Not support core %d\n", core_id); + of_node_put(child); + goto init_fail; + } + + cpdev = of_find_device_by_node(child); + if (!cpdev) { + ret = -ENODEV; + dev_err(dev, "Not found platform device for core %d\n", core_id); + of_node_put(child); + goto init_fail; + } + + scp = scp_rproc_init(cpdev, scp_cluster, cluster_of_data[core_id]); + put_device(&cpdev->dev); + if (IS_ERR(scp)) { + ret = PTR_ERR(scp); + dev_err(dev, "Failed to initialize core %d rproc\n", core_id); + of_node_put(child); + goto init_fail; + } + + ret = rproc_add(scp->rproc); + if (ret) { + dev_err(dev, "Failed to add rproc of core %d\n", core_id); + of_node_put(child); + scp_free(scp); + goto init_fail; + } + + list_add_tail(&scp->elem, scp_list); + core_id++; + } + + /* + * Here we are setting the platform device for @pdev to the last @scp that was + * created, which is needed because (1) scp_rproc_init() is calling + * platform_set_drvdata() on the child platform devices and (2) we need a handle to + * the cluster list in scp_remove(). + */ + platform_set_drvdata(pdev, scp); + + return 0; + +init_fail: + list_for_each_entry_safe_reverse(scp, temp, scp_list, elem) { + list_del(&scp->elem); + rproc_del(scp->rproc); + scp_free(scp); + } + + return ret; +} + +static int scp_is_single_core(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev_of_node(dev); + struct device_node *child; + + child = of_get_next_available_child(np, NULL); + if (!child) + return dev_err_probe(dev, -ENODEV, "No child node\n"); + + of_node_put(child); + return of_node_name_eq(child, "cros-ec-rpmsg"); +} + +static int scp_cluster_init(struct platform_device *pdev, struct mtk_scp_of_cluster *scp_cluster) +{ + int ret; + + ret = scp_is_single_core(pdev); + if (ret < 0) + return ret; + + if (ret) + ret = scp_add_single_core(pdev, scp_cluster); + else + ret = scp_add_multi_core(pdev, scp_cluster); + + return ret; +} + static int scp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1007,6 +1110,10 @@ static int scp_probe(struct platform_device *pdev) INIT_LIST_HEAD(&scp_cluster->mtk_scp_list); + ret = devm_of_platform_populate(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to populate platform devices\n"); + ret = scp_cluster_init(pdev, scp_cluster); if (ret) return ret; @@ -1101,12 +1208,19 @@ static const struct mtk_scp_of_data mt8195_of_data_c1 = { .host_to_scp_int_bit = MT8195_CORE1_HOST_IPC_INT_BIT, }; +static const struct mtk_scp_of_data *mt8195_of_data_cores[] = { + &mt8195_of_data, + &mt8195_of_data_c1, + NULL +}; + static const struct of_device_id mtk_scp_of_match[] = { { .compatible = "mediatek,mt8183-scp", .data = &mt8183_of_data }, { .compatible = "mediatek,mt8186-scp", .data = &mt8186_of_data }, { .compatible = "mediatek,mt8188-scp", .data = &mt8188_of_data }, { .compatible = "mediatek,mt8192-scp", .data = &mt8192_of_data }, { .compatible = "mediatek,mt8195-scp", .data = &mt8195_of_data }, + { .compatible = "mediatek,mt8195-scp-dual", .data = &mt8195_of_data_cores }, {}, }; MODULE_DEVICE_TABLE(of, mtk_scp_of_match); -- GitLab From c6eda63f33cbd6cff7c302869bd9a135b4a8a813 Mon Sep 17 00:00:00 2001 From: Tinghan Shen Date: Fri, 1 Sep 2023 16:09:30 +0800 Subject: [PATCH 0036/1451] remoteproc: mediatek: Remove dependency of MT8195 SCP L2TCM power control on dual-core SCP Previously, SCP core 0 controlled the power of L2TCM and dictated that SCP core 1 could only boot after SCP core 0. To address this constraint, extracted the power control flow of L2TCM and made it shared between both cores, enabling support for arbitrary boot order. The flow for controlling L2TCM power has been incorporated into the mt8195_scp_before_load() and mt8195_scp_stop() APIs, which are respectively invoked during the rproc->ops->start() and rproc->ops->stop() operations. These APIs effectively serve the same purpose as the rproc prepare()/unprepare() APIs." Signed-off-by: Tinghan Shen Reviewed-by: AngeloGioacchino Del Regno Tested-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230901080935.14571-10-tinghan.shen@mediatek.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/mtk_common.h | 3 ++ drivers/remoteproc/mtk_scp.c | 71 ++++++++++++++++++++++++++------- 2 files changed, 59 insertions(+), 15 deletions(-) diff --git a/drivers/remoteproc/mtk_common.h b/drivers/remoteproc/mtk_common.h index 1438159ae736b..fea05bbba9aa4 100644 --- a/drivers/remoteproc/mtk_common.h +++ b/drivers/remoteproc/mtk_common.h @@ -106,6 +106,9 @@ struct mtk_scp_of_cluster { size_t l1tcm_size; phys_addr_t l1tcm_phys; struct list_head mtk_scp_list; + /* Prevent concurrent operations of this structure and L2TCM power control. */ + struct mutex cluster_lock; + u32 l2tcm_refcnt; }; struct mtk_scp { diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index 4b0e1ae3a4b81..6926fd9e4c2e4 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -454,19 +454,37 @@ static int mt8192_scp_before_load(struct mtk_scp *scp) return 0; } -static int mt8195_scp_before_load(struct mtk_scp *scp) +static int mt8195_scp_l2tcm_on(struct mtk_scp *scp) { - /* clear SPM interrupt, SCP2SPM_IPC_CLR */ - writel(0xff, scp->cluster->reg_base + MT8192_SCP2SPM_IPC_CLR); + struct mtk_scp_of_cluster *scp_cluster = scp->cluster; + + mutex_lock(&scp_cluster->cluster_lock); + + if (scp_cluster->l2tcm_refcnt == 0) { + /* clear SPM interrupt, SCP2SPM_IPC_CLR */ + writel(0xff, scp->cluster->reg_base + MT8192_SCP2SPM_IPC_CLR); + + /* Power on L2TCM */ + scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_0, 0); + scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_1, 0); + scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_2, 0); + scp_sram_power_on(scp->cluster->reg_base + MT8192_L1TCM_SRAM_PDN, + MT8195_L1TCM_SRAM_PDN_RESERVED_RSI_BITS); + } + + scp_cluster->l2tcm_refcnt += 1; + mutex_unlock(&scp_cluster->cluster_lock); + + return 0; +} + +static int mt8195_scp_before_load(struct mtk_scp *scp) +{ writel(1, scp->cluster->reg_base + MT8192_CORE0_SW_RSTN_SET); - /* enable SRAM clock */ - scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_0, 0); - scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_1, 0); - scp_sram_power_on(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_2, 0); - scp_sram_power_on(scp->cluster->reg_base + MT8192_L1TCM_SRAM_PDN, - MT8195_L1TCM_SRAM_PDN_RESERVED_RSI_BITS); + mt8195_scp_l2tcm_on(scp); + scp_sram_power_on(scp->cluster->reg_base + MT8192_CPU0_SRAM_PD, 0); /* enable MPU for all memory regions */ @@ -479,6 +497,8 @@ static int mt8195_scp_c1_before_load(struct mtk_scp *scp) { scp->data->scp_reset_assert(scp); + mt8195_scp_l2tcm_on(scp); + scp_sram_power_on(scp->cluster->reg_base + MT8195_CPU1_SRAM_PD, 0); /* enable MPU for all memory regions */ @@ -645,14 +665,31 @@ static void mt8192_scp_stop(struct mtk_scp *scp) writel(0, scp->cluster->reg_base + MT8192_CORE0_WDT_CFG); } +static void mt8195_scp_l2tcm_off(struct mtk_scp *scp) +{ + struct mtk_scp_of_cluster *scp_cluster = scp->cluster; + + mutex_lock(&scp_cluster->cluster_lock); + + if (scp_cluster->l2tcm_refcnt > 0) + scp_cluster->l2tcm_refcnt -= 1; + + if (scp_cluster->l2tcm_refcnt == 0) { + /* Power off L2TCM */ + scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_0, 0); + scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_1, 0); + scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_2, 0); + scp_sram_power_off(scp->cluster->reg_base + MT8192_L1TCM_SRAM_PDN, + MT8195_L1TCM_SRAM_PDN_RESERVED_RSI_BITS); + } + + mutex_unlock(&scp_cluster->cluster_lock); +} + static void mt8195_scp_stop(struct mtk_scp *scp) { - /* Disable SRAM clock */ - scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_0, 0); - scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_1, 0); - scp_sram_power_off(scp->cluster->reg_base + MT8192_L2TCM_SRAM_PD_2, 0); - scp_sram_power_off(scp->cluster->reg_base + MT8192_L1TCM_SRAM_PDN, - MT8195_L1TCM_SRAM_PDN_RESERVED_RSI_BITS); + mt8195_scp_l2tcm_off(scp); + scp_sram_power_off(scp->cluster->reg_base + MT8192_CPU0_SRAM_PD, 0); /* Disable SCP watchdog */ @@ -661,6 +698,8 @@ static void mt8195_scp_stop(struct mtk_scp *scp) static void mt8195_scp_c1_stop(struct mtk_scp *scp) { + mt8195_scp_l2tcm_off(scp); + /* Power off CPU SRAM */ scp_sram_power_off(scp->cluster->reg_base + MT8195_CPU1_SRAM_PD, 0); @@ -1109,6 +1148,7 @@ static int scp_probe(struct platform_device *pdev) } INIT_LIST_HEAD(&scp_cluster->mtk_scp_list); + mutex_init(&scp_cluster->cluster_lock); ret = devm_of_platform_populate(dev); if (ret) @@ -1132,6 +1172,7 @@ static void scp_remove(struct platform_device *pdev) rproc_del(scp->rproc); scp_free(scp); } + mutex_destroy(&scp_cluster->cluster_lock); } static const struct mtk_scp_of_data mt8183_of_data = { -- GitLab From c01fb97cf2b55b155ee99c1ad51672f80042a922 Mon Sep 17 00:00:00 2001 From: Tinghan Shen Date: Fri, 1 Sep 2023 16:09:31 +0800 Subject: [PATCH 0037/1451] remoteproc: mediatek: Setup MT8195 SCP core 1 SRAM offset Because MT8195 SCP core 0 and core 1 both boot from head of SRAM and have the same viewpoint of SRAM, SCP has a "core 1 SRAM offset" configuration to control the access destination of SCP core 1 to boot core 1 from different SRAM location. The "core 1 SRAM offset" configuration is composed by a range and an offset. It works like a simple memory mapped mechanism. When SCP core 1 accesses a SRAM address located in the range, the SCP bus adds the configured offset to the address to shift the physical destination address on SCP SRAM. This shifting is transparent to the software running on SCP core 1. Signed-off-by: Tinghan Shen Reviewed-by: AngeloGioacchino Del Regno Tested-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230901080935.14571-11-tinghan.shen@mediatek.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/mtk_common.h | 7 +++++++ drivers/remoteproc/mtk_scp.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/drivers/remoteproc/mtk_common.h b/drivers/remoteproc/mtk_common.h index fea05bbba9aa4..3d6b53b9f3741 100644 --- a/drivers/remoteproc/mtk_common.h +++ b/drivers/remoteproc/mtk_common.h @@ -65,6 +65,13 @@ #define MT8195_CORE1_MEM_ATT_PREDEF 0x20008 #define MT8195_CORE1_WDT_CFG 0x20034 +#define MT8195_SEC_CTRL 0x85000 +#define MT8195_CORE_OFFSET_ENABLE_D BIT(13) +#define MT8195_CORE_OFFSET_ENABLE_I BIT(12) +#define MT8195_L2TCM_OFFSET_RANGE_0_LOW 0x850b0 +#define MT8195_L2TCM_OFFSET_RANGE_0_HIGH 0x850b4 +#define MT8195_L2TCM_OFFSET 0x850d0 + #define SCP_FW_VER_LEN 32 #define SCP_SHARE_BUFFER_SIZE 288 diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index 6926fd9e4c2e4..2c86695c22c24 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -495,6 +495,10 @@ static int mt8195_scp_before_load(struct mtk_scp *scp) static int mt8195_scp_c1_before_load(struct mtk_scp *scp) { + u32 sec_ctrl; + struct mtk_scp *scp_c0; + struct mtk_scp_of_cluster *scp_cluster = scp->cluster; + scp->data->scp_reset_assert(scp); mt8195_scp_l2tcm_on(scp); @@ -504,6 +508,30 @@ static int mt8195_scp_c1_before_load(struct mtk_scp *scp) /* enable MPU for all memory regions */ writel(0xff, scp->cluster->reg_base + MT8195_CORE1_MEM_ATT_PREDEF); + /* + * The L2TCM_OFFSET_RANGE and L2TCM_OFFSET shift the destination address + * on SRAM when SCP core 1 accesses SRAM. + * + * This configuration solves booting the SCP core 0 and core 1 from + * different SRAM address because core 0 and core 1 both boot from + * the head of SRAM by default. this must be configured before boot SCP core 1. + * + * The value of L2TCM_OFFSET_RANGE is from the viewpoint of SCP core 1. + * When SCP core 1 issues address within the range (L2TCM_OFFSET_RANGE), + * the address will be added with a fixed offset (L2TCM_OFFSET) on the bus. + * The shift action is tranparent to software. + */ + writel(0, scp->cluster->reg_base + MT8195_L2TCM_OFFSET_RANGE_0_LOW); + writel(scp->sram_size, scp->cluster->reg_base + MT8195_L2TCM_OFFSET_RANGE_0_HIGH); + + scp_c0 = list_first_entry(&scp_cluster->mtk_scp_list, struct mtk_scp, elem); + writel(scp->sram_phys - scp_c0->sram_phys, scp->cluster->reg_base + MT8195_L2TCM_OFFSET); + + /* enable SRAM offset when fetching instruction and data */ + sec_ctrl = readl(scp->cluster->reg_base + MT8195_SEC_CTRL); + sec_ctrl |= MT8195_CORE_OFFSET_ENABLE_I | MT8195_CORE_OFFSET_ENABLE_D; + writel(sec_ctrl, scp->cluster->reg_base + MT8195_SEC_CTRL); + return 0; } -- GitLab From 5d5cfce48069df97ae83d001187f69d63b87242f Mon Sep 17 00:00:00 2001 From: Tinghan Shen Date: Fri, 1 Sep 2023 16:09:32 +0800 Subject: [PATCH 0038/1451] remoteproc: mediatek: Handle MT8195 SCP core 1 watchdog timeout The MT8195 SCP core 1 watchdog timeout needs to be handled in the SCP core 0 IRQ handler because the MT8195 SCP core 1 watchdog timeout IRQ is wired on the same IRQ entry for core 0 watchdog timeout. MT8195 SCP has a watchdog status register to identify the watchdog timeout source when IRQ triggered. Signed-off-by: Tinghan Shen Reviewed-by: AngeloGioacchino Del Regno Tested-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230901080935.14571-12-tinghan.shen@mediatek.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/mtk_common.h | 5 +++++ drivers/remoteproc/mtk_scp.c | 25 ++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/remoteproc/mtk_common.h b/drivers/remoteproc/mtk_common.h index 3d6b53b9f3741..6d7736a031f7f 100644 --- a/drivers/remoteproc/mtk_common.h +++ b/drivers/remoteproc/mtk_common.h @@ -55,6 +55,10 @@ #define MT8192_CORE0_WDT_IRQ 0x10030 #define MT8192_CORE0_WDT_CFG 0x10034 +#define MT8195_SYS_STATUS 0x4004 +#define MT8195_CORE0_WDT BIT(16) +#define MT8195_CORE1_WDT BIT(17) + #define MT8195_L1TCM_SRAM_PDN_RESERVED_RSI_BITS GENMASK(7, 4) #define MT8195_CPU1_SRAM_PD 0x1084 @@ -63,6 +67,7 @@ #define MT8195_CORE1_SW_RSTN_CLR 0x20000 #define MT8195_CORE1_SW_RSTN_SET 0x20004 #define MT8195_CORE1_MEM_ATT_PREDEF 0x20008 +#define MT8195_CORE1_WDT_IRQ 0x20030 #define MT8195_CORE1_WDT_CFG 0x20034 #define MT8195_SEC_CTRL 0x85000 diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index 2c86695c22c24..147f56d600966 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -222,6 +222,29 @@ static void mt8192_scp_irq_handler(struct mtk_scp *scp) } } +static void mt8195_scp_irq_handler(struct mtk_scp *scp) +{ + u32 scp_to_host; + + scp_to_host = readl(scp->cluster->reg_base + MT8192_SCP2APMCU_IPC_SET); + + if (scp_to_host & MT8192_SCP_IPC_INT_BIT) { + scp_ipi_handler(scp); + } else { + u32 reason = readl(scp->cluster->reg_base + MT8195_SYS_STATUS); + + if (reason & MT8195_CORE0_WDT) + writel(1, scp->cluster->reg_base + MT8192_CORE0_WDT_IRQ); + + if (reason & MT8195_CORE1_WDT) + writel(1, scp->cluster->reg_base + MT8195_CORE1_WDT_IRQ); + + scp_wdt_handler(scp, reason); + } + + writel(scp_to_host, scp->cluster->reg_base + MT8192_SCP2APMCU_IPC_CLR); +} + static void mt8195_scp_c1_irq_handler(struct mtk_scp *scp) { u32 scp_to_host; @@ -1256,7 +1279,7 @@ static const struct mtk_scp_of_data mt8192_of_data = { static const struct mtk_scp_of_data mt8195_of_data = { .scp_clk_get = mt8195_scp_clk_get, .scp_before_load = mt8195_scp_before_load, - .scp_irq_handler = mt8192_scp_irq_handler, + .scp_irq_handler = mt8195_scp_irq_handler, .scp_reset_assert = mt8192_scp_reset_assert, .scp_reset_deassert = mt8192_scp_reset_deassert, .scp_stop = mt8195_scp_stop, -- GitLab From b0cdc6a4df7a8e0bcddd7a302229a6ae9a3e044e Mon Sep 17 00:00:00 2001 From: Tinghan Shen Date: Fri, 1 Sep 2023 16:09:33 +0800 Subject: [PATCH 0039/1451] remoteproc: mediatek: Report watchdog crash to all cores To ensure consistent behavior, the watchdog timeout handling of the multi-core SCP should reset the whole SCP sub-system when watchdog timeout. Triggering the rproc recovery flow on all instances will ensure proper recovery of the SCP sub-system. Signed-off-by: Tinghan Shen Reviewed-by: AngeloGioacchino Del Regno Tested-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230901080935.14571-13-tinghan.shen@mediatek.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/mtk_scp.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index 147f56d600966..a28c9b017f3a4 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -68,8 +68,14 @@ EXPORT_SYMBOL_GPL(scp_put); static void scp_wdt_handler(struct mtk_scp *scp, u32 scp_to_host) { + struct mtk_scp_of_cluster *scp_cluster = scp->cluster; + struct mtk_scp *scp_node; + dev_err(scp->dev, "SCP watchdog timeout! 0x%x", scp_to_host); - rproc_report_crash(scp->rproc, RPROC_WATCHDOG); + + /* report watchdog timeout to all cores */ + list_for_each_entry(scp_node, &scp_cluster->mtk_scp_list, elem) + rproc_report_crash(scp_node->rproc, RPROC_WATCHDOG); } static void scp_init_ipi_handler(void *data, unsigned int len, void *priv) -- GitLab From d1a8ac11ee72c192611b0cae98ad6304314f9ae7 Mon Sep 17 00:00:00 2001 From: Tinghan Shen Date: Fri, 1 Sep 2023 16:09:34 +0800 Subject: [PATCH 0040/1451] remoteproc: mediatek: Refine ipi handler error message The error message doesn't accurately reflect the cause of the error. The error is due to a handler not being found, not an invalid IPI ID. Signed-off-by: Tinghan Shen Reviewed-by: AngeloGioacchino Del Regno Tested-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230901080935.14571-14-tinghan.shen@mediatek.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/mtk_scp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index a28c9b017f3a4..ea227b566c543 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -112,7 +112,7 @@ static void scp_ipi_handler(struct mtk_scp *scp) scp_ipi_lock(scp, id); handler = ipi_desc[id].handler; if (!handler) { - dev_err(scp->dev, "No such ipi id = %d\n", id); + dev_err(scp->dev, "No handler for ipi id = %d\n", id); scp_ipi_unlock(scp, id); return; } -- GitLab From 9af45bbdcbbbb411b6b7440220593a46282fd64b Mon Sep 17 00:00:00 2001 From: Tanmay Shah Date: Tue, 12 Sep 2023 19:43:23 -0700 Subject: [PATCH 0041/1451] remoteproc: zynqmp: fix TCM carveouts in lockstep mode In lockstep mode following is TCM address map: | *TCM* | *R5 View* | *Linux view* | | R5_0 ATCM (128 KB) | 0x0000_0000 | 0xFFE0_0000 | | R5_0 BTCM (128 KB) | 0x0002_0000 | 0xFFE2_0000 | Current driver keeps single TCM carveout in lockstep mode as ATCM and BTCM addresses form contiguous memory region. Although the addresses are contiguous, it is not same type of memory. ATCM typically holds interrupt or exception code that must be accessed at high speed. BTCM typically holds a block of data for intensive processing, such as audio or video processing. As both are different types of memory, they should be allocated as different carveout. This patch is fixing TCM carveout allocation in lockstep mode. Signed-off-by: Tanmay Shah Link: https://lore.kernel.org/r/20230913024323.2768114-1-tanmay.shah@amd.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/xlnx_r5_remoteproc.c | 66 ++++++++++++++++--------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c index feca6de68da28..efd758c2f4ed1 100644 --- a/drivers/remoteproc/xlnx_r5_remoteproc.c +++ b/drivers/remoteproc/xlnx_r5_remoteproc.c @@ -75,13 +75,21 @@ struct mbox_info { * Hardcoded TCM bank values. This will be removed once TCM bindings are * accepted for system-dt specifications and upstreamed in linux kernel */ -static const struct mem_bank_data zynqmp_tcm_banks[] = { +static const struct mem_bank_data zynqmp_tcm_banks_split[] = { {0xffe00000UL, 0x10000UL, PD_R5_0_ATCM, "atcm0"}, /* TCM 64KB each */ {0xffe20000UL, 0x10000UL, PD_R5_0_BTCM, "btcm0"}, {0xffe90000UL, 0x10000UL, PD_R5_1_ATCM, "atcm1"}, {0xffeb0000UL, 0x10000UL, PD_R5_1_BTCM, "btcm1"}, }; +/* In lockstep mode cluster combines each 64KB TCM and makes 128KB TCM */ +static const struct mem_bank_data zynqmp_tcm_banks_lockstep[] = { + {0xffe00000UL, 0x20000UL, PD_R5_0_ATCM, "atcm0"}, /* TCM 128KB each */ + {0xffe20000UL, 0x20000UL, PD_R5_0_BTCM, "btcm0"}, + {0, 0, PD_R5_1_ATCM, ""}, + {0, 0, PD_R5_1_BTCM, ""}, +}; + /** * struct zynqmp_r5_core * @@ -650,14 +658,11 @@ static int add_tcm_carveout_lockstep_mode(struct rproc *rproc) /* * In lockstep mode, TCM is contiguous memory block * However, each TCM block still needs to be enabled individually. - * So, Enable each TCM block individually, but add their size - * to create contiguous memory region. + * So, Enable each TCM block individually. + * Although ATCM and BTCM is contiguous memory block, add two separate + * carveouts for both. */ - bank_addr = r5_core->tcm_banks[0]->addr; - bank_name = r5_core->tcm_banks[0]->bank_name; - for (i = 0; i < num_banks; i++) { - bank_size += r5_core->tcm_banks[i]->size; pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; /* Turn on each TCM bank individually */ @@ -668,23 +673,31 @@ static int add_tcm_carveout_lockstep_mode(struct rproc *rproc) dev_err(dev, "failed to turn on TCM 0x%x", pm_domain_id); goto release_tcm_lockstep; } - } - dev_dbg(dev, "TCM add carveout lockstep mode %s addr=0x%llx, size=0x%lx", - bank_name, bank_addr, bank_size); - - /* Register TCM address range, TCM map and unmap functions */ - rproc_mem = rproc_mem_entry_init(dev, NULL, bank_addr, - bank_size, bank_addr, - tcm_mem_map, tcm_mem_unmap, - bank_name); - if (!rproc_mem) { - ret = -ENOMEM; - goto release_tcm_lockstep; - } + bank_size = r5_core->tcm_banks[i]->size; + if (bank_size == 0) + continue; - /* If registration is success, add carveouts */ - rproc_add_carveout(rproc, rproc_mem); + bank_addr = r5_core->tcm_banks[i]->addr; + bank_name = r5_core->tcm_banks[i]->bank_name; + + /* Register TCM address range, TCM map and unmap functions */ + rproc_mem = rproc_mem_entry_init(dev, NULL, bank_addr, + bank_size, bank_addr, + tcm_mem_map, tcm_mem_unmap, + bank_name); + if (!rproc_mem) { + ret = -ENOMEM; + zynqmp_pm_release_node(pm_domain_id); + goto release_tcm_lockstep; + } + + /* If registration is success, add carveouts */ + rproc_add_carveout(rproc, rproc_mem); + + dev_dbg(dev, "TCM add carveout lockstep mode %s addr=0x%llx, size=0x%lx", + bank_name, bank_addr, bank_size); + } return 0; @@ -895,12 +908,19 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev) */ static int zynqmp_r5_get_tcm_node(struct zynqmp_r5_cluster *cluster) { + const struct mem_bank_data *zynqmp_tcm_banks; struct device *dev = cluster->dev; struct zynqmp_r5_core *r5_core; int tcm_bank_count, tcm_node; int i, j; - tcm_bank_count = ARRAY_SIZE(zynqmp_tcm_banks); + if (cluster->mode == SPLIT_MODE) { + zynqmp_tcm_banks = zynqmp_tcm_banks_split; + tcm_bank_count = ARRAY_SIZE(zynqmp_tcm_banks_split); + } else { + zynqmp_tcm_banks = zynqmp_tcm_banks_lockstep; + tcm_bank_count = ARRAY_SIZE(zynqmp_tcm_banks_lockstep); + } /* count per core tcm banks */ tcm_bank_count = tcm_bank_count / cluster->core_count; -- GitLab From 18c1db313ea904ebd01aa08135b72cdb04f889fb Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Sun, 11 Dec 2022 21:25:39 +0100 Subject: [PATCH 0042/1451] gfs2: Simplify function gfs2_upgrade_iopen_glock When trying to upgrade the iopen glock, gfs2_upgrade_iopen_glock() tries to take the iopen glock with the LM_FLAG_TRY_1CB flag set before trying to take it without the LM_FLAG_TRY or LM_FLAG_TRY_1CB flags set. Both calls will cause the lock contention bast callbacks to be invoked throughout the cluster, and we really don't need them to be invoked twice. Remove the first LM_FLAG_TRY_1CB call to eliminate unnecessary dlm traffic. Signed-off-by: Andreas Gruenbacher --- fs/gfs2/super.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 02d93da21b2b0..3141db77189e9 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1299,18 +1299,8 @@ static bool gfs2_upgrade_iopen_glock(struct inode *inode) * As a last resort, if another node keeps holding the iopen glock * without showing any activity on the inode glock, we will eventually * time out and fail the iopen glock upgrade. - * - * Note that we're passing the LM_FLAG_TRY_1CB flag to the first - * locking request as an optimization to notify lock holders as soon as - * possible. Without that flag, they'd be notified implicitly by the - * second locking request. */ - gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, gh); - error = gfs2_glock_nq(gh); - if (error != GLR_TRYFAILED) - return !error; - gfs2_holder_reinit(LM_ST_EXCLUSIVE, GL_ASYNC | GL_NOCACHE, gh); error = gfs2_glock_nq(gh); if (error) -- GitLab From bbacb395ac5c57290cdfd02389788cbce64c237e Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 1 Sep 2023 21:39:26 +0200 Subject: [PATCH 0043/1451] gfs2: Remove freeze_go_demote_ok Before commit b77b4a4815a9 ("gfs2: Rework freeze / thaw logic"), the freeze glock was kept around in the glock cache in shared mode without being actively held while a filesystem is in thawed state. In that state, memory pressure could have eventually evicted the freeze glock, and the freeze_go_demote_ok callback was needed to prevent that from happening. With the freeze / thaw rework, the freeze glock is now always actively held in shared mode while a filesystem is thawed, and the freeze_go_demote_ok hack is no longer needed. Signed-off-by: Andreas Gruenbacher --- fs/gfs2/glops.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index f41ca89d216bc..5f845fd9f13a4 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -613,18 +613,6 @@ static int freeze_go_xmote_bh(struct gfs2_glock *gl) return 0; } -/** - * freeze_go_demote_ok - * @gl: the glock - * - * Always returns 0 - */ - -static int freeze_go_demote_ok(const struct gfs2_glock *gl) -{ - return 0; -} - /** * iopen_go_callback - schedule the dcache entry for the inode to be deleted * @gl: the glock @@ -744,7 +732,6 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = { const struct gfs2_glock_operations gfs2_freeze_glops = { .go_xmote_bh = freeze_go_xmote_bh, - .go_demote_ok = freeze_go_demote_ok, .go_callback = freeze_go_callback, .go_type = LM_TYPE_NONDISK, .go_flags = GLOF_NONDISK, -- GitLab From b4bf3d5c37d404b05356869cdbd16450f3ba02a0 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 14 Sep 2023 23:47:07 +0200 Subject: [PATCH 0044/1451] gfs2: Remove unused gfs2_extent_length argument The limit argument of gfs2_extent_length() is unused. Signed-off-by: Andreas Gruenbacher --- fs/gfs2/bmap.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index ef7017fb69512..47d0f39feeb1f 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -415,13 +415,12 @@ static void release_metapath(struct metapath *mp) * gfs2_extent_length - Returns length of an extent of blocks * @bh: The metadata block * @ptr: Current position in @bh - * @limit: Max extent length to return * @eob: Set to 1 if we hit "end of block" * * Returns: The length of the extent (minimum of one block) */ -static inline unsigned int gfs2_extent_length(struct buffer_head *bh, __be64 *ptr, size_t limit, int *eob) +static inline unsigned int gfs2_extent_length(struct buffer_head *bh, __be64 *ptr, int *eob) { const __be64 *end = (__be64 *)(bh->b_data + bh->b_size); const __be64 *first = ptr; @@ -913,7 +912,7 @@ static int __gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length, goto do_alloc; bh = mp->mp_bh[ip->i_height - 1]; - len = gfs2_extent_length(bh, ptr, len, &eob); + len = gfs2_extent_length(bh, ptr, &eob); iomap->addr = be64_to_cpu(*ptr) << inode->i_blkbits; iomap->length = len << inode->i_blkbits; -- GitLab From 796a35f19400bab757b4325e05ec4333d27028fa Mon Sep 17 00:00:00 2001 From: Tinghan Shen Date: Fri, 1 Sep 2023 16:09:23 +0800 Subject: [PATCH 0045/1451] arm64: dts: mediatek: Update the node name of SCP rpmsg subnode Align the node name with the definition in SCP bindings. Signed-off-by: Tinghan Shen Reviewed-by: AngeloGioacchino Del Regno Acked-by: Matthias Brugger Link: https://lore.kernel.org/r/20230901080935.14571-3-tinghan.shen@mediatek.com Signed-off-by: Mathieu Poirier --- arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi | 2 +- arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi index 6ce16a265e053..34076ba28fd0c 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi @@ -831,7 +831,7 @@ &scp { pinctrl-names = "default"; pinctrl-0 = <&scp_pins>; - cros_ec { + cros-ec-rpmsg { compatible = "google,cros-ec-rpmsg"; mediatek,rpmsg-name = "cros-ec-rpmsg"; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi b/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi index 0e8b341170907..1bbc994bc109d 100644 --- a/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi @@ -1284,7 +1284,7 @@ &scp { pinctrl-names = "default"; pinctrl-0 = <&scp_pins>; - cros-ec { + cros-ec-rpmsg { compatible = "google,cros-ec-rpmsg"; mediatek,rpmsg-name = "cros-ec-rpmsg"; }; -- GitLab From 04a6a8eb1375c1c1f3a735c5715854ce8a3f3730 Mon Sep 17 00:00:00 2001 From: Song Shuai Date: Thu, 7 Sep 2023 18:33:02 +0800 Subject: [PATCH 0046/1451] riscv: kexec: Cleanup riscv_kexec_relocate For readability and simplicity, cleanup the riscv_kexec_relocate code: - Re-sort the first 4 `mv` instructions against `riscv_kexec_method()` - Eliminate registers for debugging (s9,s10,s11) and storing const-value (s5,s6) - Replace `jalr` with `jr` for no-link jump I tested this on Qemu virt machine and works as it was. Signed-off-by: Song Shuai Link: https://lore.kernel.org/r/20230907103304.590739-2-songshuaishuai@tinylab.org Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/kexec_relocate.S | 52 +++++++++++++----------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/arch/riscv/kernel/kexec_relocate.S b/arch/riscv/kernel/kexec_relocate.S index 059c5e216ae75..de0a4b35d01ef 100644 --- a/arch/riscv/kernel/kexec_relocate.S +++ b/arch/riscv/kernel/kexec_relocate.S @@ -17,27 +17,17 @@ SYM_CODE_START(riscv_kexec_relocate) * s1: (const) Phys address to jump to after relocation * s2: (const) Phys address of the FDT image * s3: (const) The hartid of the current hart - * s4: Pointer to the destination address for the relocation - * s5: (const) Number of words per page - * s6: (const) 1, used for subtraction - * s7: (const) kernel_map.va_pa_offset, used when switching MMU off - * s8: (const) Physical address of the main loop - * s9: (debug) indirection page counter - * s10: (debug) entry counter - * s11: (debug) copied words counter + * s4: (const) kernel_map.va_pa_offset, used when switching MMU off + * s5: Pointer to the destination address for the relocation + * s6: (const) Physical address of the main loop */ mv s0, a0 mv s1, a1 mv s2, a2 mv s3, a3 - mv s4, zero - li s5, (PAGE_SIZE / RISCV_SZPTR) - li s6, 1 - mv s7, a4 - mv s8, zero - mv s9, zero - mv s10, zero - mv s11, zero + mv s4, a4 + mv s5, zero + mv s6, zero /* Disable / cleanup interrupts */ csrw CSR_SIE, zero @@ -52,21 +42,27 @@ SYM_CODE_START(riscv_kexec_relocate) * the start of the loop below so that we jump there in * any case. */ - la s8, 1f - sub s8, s8, s7 - csrw CSR_STVEC, s8 + la s6, 1f + sub s6, s6, s4 + csrw CSR_STVEC, s6 + + /* + * With C-extension, here we get 42 Bytes and the next + * .align directive would pad zeros here up to 44 Bytes. + * So manually put a nop here to avoid zeros padding. + */ + nop /* Process entries in a loop */ .align 2 1: - addi s10, s10, 1 REG_L t0, 0(s0) /* t0 = *image->entry */ addi s0, s0, RISCV_SZPTR /* image->entry++ */ /* IND_DESTINATION entry ? -> save destination address */ andi t1, t0, 0x1 beqz t1, 2f - andi s4, t0, ~0x1 + andi s5, t0, ~0x1 j 1b 2: @@ -74,9 +70,8 @@ SYM_CODE_START(riscv_kexec_relocate) andi t1, t0, 0x2 beqz t1, 2f andi s0, t0, ~0x2 - addi s9, s9, 1 csrw CSR_SATP, zero - jalr zero, s8, 0 + jr s6 2: /* IND_DONE entry ? -> jump to done label */ @@ -92,14 +87,13 @@ SYM_CODE_START(riscv_kexec_relocate) andi t1, t0, 0x8 beqz t1, 1b /* Unknown entry type, ignore it */ andi t0, t0, ~0x8 - mv t3, s5 /* i = num words per page */ + li t3, (PAGE_SIZE / RISCV_SZPTR) /* i = num words per page */ 3: /* copy loop */ REG_L t1, (t0) /* t1 = *src_ptr */ - REG_S t1, (s4) /* *dst_ptr = *src_ptr */ + REG_S t1, (s5) /* *dst_ptr = *src_ptr */ addi t0, t0, RISCV_SZPTR /* stc_ptr++ */ - addi s4, s4, RISCV_SZPTR /* dst_ptr++ */ - sub t3, t3, s6 /* i-- */ - addi s11, s11, 1 /* c++ */ + addi s5, s5, RISCV_SZPTR /* dst_ptr++ */ + addi t3, t3, -0x1 /* i-- */ beqz t3, 1b /* copy done ? */ j 3b @@ -146,7 +140,7 @@ SYM_CODE_START(riscv_kexec_relocate) */ fence.i - jalr zero, a2, 0 + jr a2 SYM_CODE_END(riscv_kexec_relocate) riscv_kexec_relocate_end: -- GitLab From 767423658d53d147409821e51e6d0bc12425b24f Mon Sep 17 00:00:00 2001 From: Song Shuai Date: Thu, 7 Sep 2023 18:33:03 +0800 Subject: [PATCH 0047/1451] riscv: kexec: Align the kexeced kernel entry The current riscv boot protocol requires 2MB alignment for RV64 and 4MB alignment for RV32. In KEXEC_FILE path, the elf_find_pbase() function should align the kexeced kernel entry according to the requirement, otherwise the kexeced kernel would silently BUG at the setup_vm(). Fixes: 8acea455fafa ("RISC-V: Support for kexec_file on panic") Signed-off-by: Song Shuai Link: https://lore.kernel.org/r/20230907103304.590739-3-songshuaishuai@tinylab.org Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/elf_kexec.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/riscv/kernel/elf_kexec.c b/arch/riscv/kernel/elf_kexec.c index 5372b708fae21..9a81d6926ac61 100644 --- a/arch/riscv/kernel/elf_kexec.c +++ b/arch/riscv/kernel/elf_kexec.c @@ -98,7 +98,13 @@ static int elf_find_pbase(struct kimage *image, unsigned long kernel_len, kbuf.image = image; kbuf.buf_min = lowest_paddr; kbuf.buf_max = ULONG_MAX; - kbuf.buf_align = PAGE_SIZE; + + /* + * Current riscv boot protocol requires 2MB alignment for + * RV64 and 4MB alignment for RV32 + * + */ + kbuf.buf_align = PMD_SIZE; kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; kbuf.memsz = ALIGN(kernel_len, PAGE_SIZE); kbuf.top_down = false; -- GitLab From 0f5f46a869a5e82fde7a208fbde6f3846972c72a Mon Sep 17 00:00:00 2001 From: Song Shuai Date: Thu, 7 Sep 2023 18:33:04 +0800 Subject: [PATCH 0048/1451] riscv: kexec: Remove -fPIE for PURGATORY_CFLAGS With CONFIG_RELOCATABLE enabled, KBUILD_CFLAGS had a -fPIE option and then the purgatory/string.o was built to reference _ctype symbol via R_RISCV_GOT_HI20 relocations which can't be handled by purgatory. As a consequence, the kernel failed kexec_load_file() with: [ 880.386562] kexec_image: The entry point of kernel at 0x80200000 [ 880.388650] kexec_image: Unknown rela relocation: 20 [ 880.389173] kexec_image: Error loading purgatory ret=-8 So remove the -fPIE option for PURGATORY_CFLAGS to generate R_RISCV_PCREL_HI20 relocations type making puragtory work as it was. Fixes: 39b33072941f ("riscv: Introduce CONFIG_RELOCATABLE") Signed-off-by: Song Shuai Link: https://lore.kernel.org/r/20230907103304.590739-4-songshuaishuai@tinylab.org Signed-off-by: Palmer Dabbelt --- arch/riscv/purgatory/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/riscv/purgatory/Makefile b/arch/riscv/purgatory/Makefile index dc20e166983e3..c2065d63945f3 100644 --- a/arch/riscv/purgatory/Makefile +++ b/arch/riscv/purgatory/Makefile @@ -77,6 +77,10 @@ ifdef CONFIG_STACKPROTECTOR_STRONG PURGATORY_CFLAGS_REMOVE += -fstack-protector-strong endif +ifdef CONFIG_RELOCATABLE +PURGATORY_CFLAGS_REMOVE += -fPIE +endif + CFLAGS_REMOVE_purgatory.o += $(PURGATORY_CFLAGS_REMOVE) CFLAGS_purgatory.o += $(PURGATORY_CFLAGS) -- GitLab From eadadb9510f7e45d2dca602ec261518a65e349f8 Mon Sep 17 00:00:00 2001 From: Nikita Travkin Date: Thu, 7 Sep 2023 15:02:34 +0500 Subject: [PATCH 0049/1451] dt-bindings: remoteproc: qcom: sc7180-pas: Add ADSP compatible SC7180 has an ADSP remoteproc. Add it's compatible to the bindings and refactor the schema conditionals to fit the ADSP. Signed-off-by: Nikita Travkin Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230907-sc7180-adsp-rproc-v3-1-6515c3fbe0a3@trvn.ru Signed-off-by: Bjorn Andersson --- .../bindings/remoteproc/qcom,sc7180-pas.yaml | 81 +++++++++++++------ 1 file changed, 56 insertions(+), 25 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-pas.yaml index 689d5d5353318..f10f329677d84 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-pas.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-pas.yaml @@ -16,6 +16,7 @@ description: properties: compatible: enum: + - qcom,sc7180-adsp-pas - qcom,sc7180-mpss-pas - qcom,sc7280-mpss-pas @@ -30,26 +31,6 @@ properties: items: - const: xo - interrupts: - minItems: 6 - - interrupt-names: - minItems: 6 - - power-domains: - minItems: 2 - items: - - description: CX power domain - - description: MX power domain - - description: MSS power domain - - power-domain-names: - minItems: 2 - items: - - const: cx - - const: mx - - const: mss - memory-region: maxItems: 1 description: Reference to the reserved-memory for the Hexagon core @@ -71,6 +52,40 @@ required: allOf: - $ref: /schemas/remoteproc/qcom,pas-common.yaml# + - if: + properties: + compatible: + enum: + - qcom,sc7180-adsp-pas + then: + properties: + interrupts: + maxItems: 5 + interrupt-names: + maxItems: 5 + else: + properties: + interrupts: + minItems: 6 + interrupt-names: + minItems: 6 + + - if: + properties: + compatible: + enum: + - qcom,sc7180-adsp-pas + then: + properties: + power-domains: + items: + - description: LCX power domain + - description: LMX power domain + power-domain-names: + items: + - const: lcx + - const: lmx + - if: properties: compatible: @@ -79,15 +94,31 @@ allOf: then: properties: power-domains: - minItems: 3 + items: + - description: CX power domain + - description: MX power domain + - description: MSS power domain power-domain-names: - minItems: 3 - else: + items: + - const: cx + - const: mx + - const: mss + + - if: + properties: + compatible: + enum: + - qcom,sc7280-mpss-pas + then: properties: power-domains: - maxItems: 2 + items: + - description: CX power domain + - description: MX power domain power-domain-names: - maxItems: 2 + items: + - const: cx + - const: mx unevaluatedProperties: false -- GitLab From 8de60bbab994bf8165d7d10e974872852da47aa7 Mon Sep 17 00:00:00 2001 From: Nikita Travkin Date: Thu, 7 Sep 2023 15:02:35 +0500 Subject: [PATCH 0050/1451] remoteproc: qcom: pas: Add sc7180 adsp sc7180 has a dedicated ADSP similar to the one found in sm8250. Add it's compatible to the driver reusing the existing config so the devices that use the adsp can probe it. Signed-off-by: Nikita Travkin Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20230907-sc7180-adsp-rproc-v3-2-6515c3fbe0a3@trvn.ru Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pas.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index b5447dd2dd35e..55fafc68200e7 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -1161,6 +1161,7 @@ static const struct of_device_id adsp_of_match[] = { { .compatible = "qcom,qcs404-adsp-pas", .data = &adsp_resource_init }, { .compatible = "qcom,qcs404-cdsp-pas", .data = &cdsp_resource_init }, { .compatible = "qcom,qcs404-wcss-pas", .data = &wcss_resource_init }, + { .compatible = "qcom,sc7180-adsp-pas", .data = &sm8250_adsp_resource}, { .compatible = "qcom,sc7180-mpss-pas", .data = &mpss_resource_init}, { .compatible = "qcom,sc7280-mpss-pas", .data = &mpss_resource_init}, { .compatible = "qcom,sc8180x-adsp-pas", .data = &sm8150_adsp_resource}, -- GitLab From d93f191b95bec3c913978eb18c6297e797915993 Mon Sep 17 00:00:00 2001 From: MD Danish Anwar Date: Mon, 14 Aug 2023 15:21:41 +0530 Subject: [PATCH 0051/1451] dt-bindings: remoteproc: pru: Add Interrupt property Add interrupts and interrupt-names protperties for PRU and RTU cores. Signed-off-by: MD Danish Anwar Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20230814095141.3526684-1-danishanwar@ti.com Signed-off-by: Bjorn Andersson --- .../bindings/remoteproc/ti,pru-rproc.yaml | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.yaml index baccd98754a90..faf16cf140851 100644 --- a/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.yaml +++ b/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.yaml @@ -66,6 +66,17 @@ properties: Should contain the name of the default firmware image file located on the firmware search path. + interrupts: + maxItems: 1 + description: + Interrupt specifiers enable the virtio/rpmsg communication between MPU + and the PRU/RTU cores. For the values of the interrupt cells please refer + to interrupt-controller/ti,pruss-intc.yaml schema. + + interrupt-names: + items: + - const: vring + if: properties: compatible: @@ -171,6 +182,9 @@ examples: <0x22400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am65x-pru0_0-fw"; + interrupt-parent = <&icssg0_intc>; + interrupts = <16 2 2>; + interrupt-names = "vring"; }; rtu0_0: rtu@4000 { @@ -180,6 +194,9 @@ examples: <0x23400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am65x-rtu0_0-fw"; + interrupt-parent = <&icssg0_intc>; + interrupts = <20 4 4>; + interrupt-names = "vring"; }; tx_pru0_0: txpru@a000 { @@ -198,6 +215,9 @@ examples: <0x24400 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am65x-pru0_1-fw"; + interrupt-parent = <&icssg0_intc>; + interrupts = <18 3 3>; + interrupt-names = "vring"; }; rtu0_1: rtu@6000 { @@ -207,6 +227,9 @@ examples: <0x23c00 0x100>; reg-names = "iram", "control", "debug"; firmware-name = "am65x-rtu0_1-fw"; + interrupt-parent = <&icssg0_intc>; + interrupts = <22 5 5>; + interrupt-names = "vring"; }; tx_pru0_1: txpru@c000 { -- GitLab From 6d3211e015b0f236986b16c042f71cce8d36d727 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 27 Jul 2023 19:33:21 +0200 Subject: [PATCH 0052/1451] dt-bindings: remoteproc: qcom,sm6375-pas: Document remoteprocs SM6375 hosts an ADSP, CDSP and modem as remote processors. Create related bindings. Signed-off-by: Konrad Dybcio Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230725-topic-6375_rproc-v5-1-a8e9cde56a20@linaro.org Signed-off-by: Bjorn Andersson --- .../bindings/remoteproc/qcom,sm6375-pas.yaml | 145 ++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 Documentation/devicetree/bindings/remoteproc/qcom,sm6375-pas.yaml diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sm6375-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sm6375-pas.yaml new file mode 100644 index 0000000000000..3e4a03eb4532b --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/qcom,sm6375-pas.yaml @@ -0,0 +1,145 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/remoteproc/qcom,sm6375-pas.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SM6375 Peripheral Authentication Service + +maintainers: + - Manivannan Sadhasivam + +description: + Qualcomm SM6375 SoC Peripheral Authentication Service loads and boots + firmware on the Qualcomm DSP Hexagon cores. + +properties: + compatible: + enum: + - qcom,sm6375-adsp-pas + - qcom,sm6375-cdsp-pas + - qcom,sm6375-mpss-pas + + reg: + maxItems: 1 + + clocks: + items: + - description: XO clock + + clock-names: + items: + - const: xo + + memory-region: + maxItems: 1 + description: Reference to the reserved-memory for the Hexagon core + + firmware-name: + $ref: /schemas/types.yaml#/definitions/string + description: Firmware name for the Hexagon core + + smd-edge: false + +required: + - compatible + - reg + +allOf: + - $ref: /schemas/remoteproc/qcom,pas-common.yaml# + - if: + properties: + compatible: + enum: + - qcom,sm6375-adsp-pas + - qcom,sm6375-cdsp-pas + then: + properties: + interrupts: + maxItems: 5 + interrupt-names: + maxItems: 5 + else: + properties: + interrupts: + minItems: 6 + interrupt-names: + minItems: 6 + + - if: + properties: + compatible: + enum: + - qcom,sm6375-adsp-pas + then: + properties: + power-domains: + items: + - description: LCX power domain + - description: LMX power domain + power-domain-names: + items: + - const: lcx + - const: lmx + + - if: + properties: + compatible: + enum: + - qcom,sm6375-cdsp-pas + - qcom,sm6375-mpss-pas + then: + properties: + power-domains: + items: + - description: CX power domain + power-domain-names: + items: + - const: cx + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + + remoteproc_adsp: remoteproc@a400000 { + compatible = "qcom,sm6375-adsp-pas"; + reg = <0x0a400000 0x100>; + + interrupts-extended = <&intc GIC_SPI 282 IRQ_TYPE_LEVEL_HIGH>, + <&smp2p_adsp_in 0 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 1 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 2 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 3 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", "fatal", "ready", + "handover", "stop-ack"; + + clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>; + clock-names = "xo"; + + power-domains = <&rpmpd SM6375_VDD_LPI_CX>, + <&rpmpd SM6375_VDD_LPI_MX>; + power-domain-names = "lcx", "lmx"; + + memory-region = <&pil_adsp_mem>; + + qcom,smem-states = <&smp2p_adsp_out 0>; + qcom,smem-state-names = "stop"; + + glink-edge { + interrupts-extended = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_GLINK_QMP>; + + label = "lpass"; + qcom,remote-pid = <2>; + + /* ... */ + }; + }; -- GitLab From a6df21cf0c93cab57059e2592c7c99b424965374 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 27 Jul 2023 19:33:22 +0200 Subject: [PATCH 0053/1451] remoteproc: qcom: pas: Add SM6375 ADSP & CDSP Add a config for the ADSP&CDSP present on SM6375. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230725-topic-6375_rproc-v5-2-a8e9cde56a20@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pas.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 55fafc68200e7..7d5b2d9213dfb 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -1181,6 +1181,8 @@ static const struct of_device_id adsp_of_match[] = { { .compatible = "qcom,sm6350-adsp-pas", .data = &sm6350_adsp_resource}, { .compatible = "qcom,sm6350-cdsp-pas", .data = &sm6350_cdsp_resource}, { .compatible = "qcom,sm6350-mpss-pas", .data = &mpss_resource_init}, + { .compatible = "qcom,sm6375-adsp-pas", .data = &sm6350_adsp_resource}, + { .compatible = "qcom,sm6375-cdsp-pas", .data = &sm8150_cdsp_resource}, { .compatible = "qcom,sm8150-adsp-pas", .data = &sm8150_adsp_resource}, { .compatible = "qcom,sm8150-cdsp-pas", .data = &sm8150_cdsp_resource}, { .compatible = "qcom,sm8150-mpss-pas", .data = &mpss_resource_init}, -- GitLab From 93f875645c9da9c788224964499e68fa9664e80f Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 27 Jul 2023 19:33:23 +0200 Subject: [PATCH 0054/1451] remoteproc: qcom: pas: Add SM6375 MPSS Add a config for the MPSS present on SM6375. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230725-topic-6375_rproc-v5-3-a8e9cde56a20@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pas.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 7d5b2d9213dfb..913a5d2068e8c 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -813,6 +813,21 @@ static const struct adsp_data sm6350_adsp_resource = { .ssctl_id = 0x14, }; +static const struct adsp_data sm6375_mpss_resource = { + .crash_reason_smem = 421, + .firmware_name = "modem.mdt", + .pas_id = 4, + .minidump_id = 3, + .auto_boot = false, + .proxy_pd_names = (char*[]){ + "cx", + NULL + }, + .ssr_name = "mpss", + .sysmon_name = "modem", + .ssctl_id = 0x12, +}; + static const struct adsp_data sm8150_adsp_resource = { .crash_reason_smem = 423, .firmware_name = "adsp.mdt", @@ -1183,6 +1198,7 @@ static const struct of_device_id adsp_of_match[] = { { .compatible = "qcom,sm6350-mpss-pas", .data = &mpss_resource_init}, { .compatible = "qcom,sm6375-adsp-pas", .data = &sm6350_adsp_resource}, { .compatible = "qcom,sm6375-cdsp-pas", .data = &sm8150_cdsp_resource}, + { .compatible = "qcom,sm6375-mpss-pas", .data = &sm6375_mpss_resource}, { .compatible = "qcom,sm8150-adsp-pas", .data = &sm8150_adsp_resource}, { .compatible = "qcom,sm8150-cdsp-pas", .data = &sm8150_cdsp_resource}, { .compatible = "qcom,sm8150-mpss-pas", .data = &mpss_resource_init}, -- GitLab From c4c5b47958529bc1de10260df0c583710853b516 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Tue, 12 Sep 2023 15:31:46 +0200 Subject: [PATCH 0055/1451] dt-bindings: remoteproc: qcom,adsp: Remove AGGRE2 clock The AGGRE2 clock is a clock for the entire AGGRE2 bus, managed from within the interconnect driver. Attaching it to SLPI was a total hack. Get rid of it. Signed-off-by: Konrad Dybcio Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230721-topic-rpm_clk_cleanup-v2-8-1e506593b1bd@linaro.org Signed-off-by: Bjorn Andersson --- .../bindings/remoteproc/qcom,adsp.yaml | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml index a2b0079de0390..661c2b425da35 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml @@ -66,7 +66,9 @@ allOf: - qcom,msm8953-adsp-pil - qcom,msm8974-adsp-pil - qcom,msm8996-adsp-pil + - qcom,msm8996-slpi-pil - qcom,msm8998-adsp-pas + - qcom,msm8998-slpi-pas - qcom,sdm845-adsp-pas - qcom,sdm845-cdsp-pas - qcom,sdm845-slpi-pas @@ -79,24 +81,6 @@ allOf: items: - const: xo - - if: - properties: - compatible: - contains: - enum: - - qcom,msm8996-slpi-pil - - qcom,msm8998-slpi-pas - then: - properties: - clocks: - items: - - description: XO clock - - description: AGGRE2 clock - clock-names: - items: - - const: xo - - const: aggre2 - - if: properties: compatible: -- GitLab From e7781901449cbcff129d80a5d9021e9e96084ec4 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Tue, 12 Sep 2023 15:31:47 +0200 Subject: [PATCH 0056/1451] dt-bindings: remoteproc: qcom,msm8996-mss-pil: Remove PNoC clock The PNoC clock is a clock for the entire PNoC bus, managed from within the interconnect driver. Attaching it to MSS was a total hack. Get rid of it. Acked-by: Krzysztof Kozlowski Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230721-topic-rpm_clk_cleanup-v2-9-1e506593b1bd@linaro.org Signed-off-by: Bjorn Andersson --- .../devicetree/bindings/remoteproc/qcom,msm8996-mss-pil.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,msm8996-mss-pil.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,msm8996-mss-pil.yaml index 0643faae2c394..971734085d512 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,msm8996-mss-pil.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,msm8996-mss-pil.yaml @@ -220,7 +220,6 @@ allOf: - description: GCC MSS GPLL0 clock - description: GCC MSS SNOC_AXI clock - description: GCC MSS MNOC_AXI clock - - description: RPM PNOC clock - description: RPM QDSS clock clock-names: items: @@ -231,7 +230,6 @@ allOf: - const: gpll0_mss - const: snoc_axi - const: mnoc_axi - - const: pnoc - const: qdss glink-edge: false required: -- GitLab From e1592981c51bac38ea2041b642777b3ba30606a8 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Tue, 12 Sep 2023 15:31:48 +0200 Subject: [PATCH 0057/1451] remoteproc: qcom: q6v5-mss: Remove PNoC clock from 8996 MSS The PNoC clock is a clock for the entire PNoC bus, managed from within the interconnect driver. Attaching it to MSS was a total hack. Get rid of it. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230721-topic-rpm_clk_cleanup-v2-10-1e506593b1bd@linaro.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_mss.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 22fe7b5f5236d..394b2c1cb5e21 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -2322,7 +2322,6 @@ static const struct rproc_hexagon_res msm8996_mss = { }, .proxy_clk_names = (char*[]){ "xo", - "pnoc", "qdss", NULL }, -- GitLab From 181f2a28d6884eee139a1aab5fc0ad5432b3caba Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 18 Sep 2023 15:15:20 +0200 Subject: [PATCH 0058/1451] RISC-V: Make zicbom/zicboz errors consistent commit c818fea83de4 ("riscv: say disabling zicbom if no or bad riscv,cbom-block-size found") improved the error messages for zicbom but zicboz was missed since its patches were in flight at the same time. Get 'em now. Signed-off-by: Andrew Jones Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20230918131518.56803-9-ajones@ventanamicro.com Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/cpufeature.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index 1cfbba65d11ae..f9ac2717bc7d7 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -93,10 +93,10 @@ static bool riscv_isa_extension_check(int id) return true; case RISCV_ISA_EXT_ZICBOZ: if (!riscv_cboz_block_size) { - pr_err("Zicboz detected in ISA string, but no cboz-block-size found\n"); + pr_err("Zicboz detected in ISA string, disabling as no cboz-block-size found\n"); return false; } else if (!is_power_of_2(riscv_cboz_block_size)) { - pr_err("cboz-block-size present, but is not a power-of-2\n"); + pr_err("Zicboz disabled as cboz-block-size present, but is not a power-of-2\n"); return false; } return true; -- GitLab From 43c16d51a19b0ba2ed66978d5924d486ec1e42bc Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 18 Sep 2023 15:15:21 +0200 Subject: [PATCH 0059/1451] RISC-V: Enable cbo.zero in usermode When Zicboz is present, enable its instruction (cbo.zero) in usermode by setting its respective senvcfg bit. We don't bother trying to set this bit per-task, which would also require an interface for tasks to request enabling and/or disabling. Instead, permanently set the bit for each hart which has the extension when bringing it online. This patch also introduces riscv_cpu_has_extension_[un]likely() functions to check a specific hart's ISA bitmap for extensions. Prior to checking the specific hart's bitmap in these functions we try the bitmap which represents the LCD of extensions, but only when we know it will use its optimized, alternatives path by gating its call on CONFIG_RISCV_ALTERNATIVE. When alternatives are used, the compiler ensures that the invocation of the LCD search becomes a constant true or false. When it's true, even the new functions will completely vanish from their callsites. OTOH, when the LCD check is false, we need to do a search of the hart's ISA bitmap. Had we also checked the LCD bitmap without the use of alternatives, then we would have ended up with two bitmap searches instead of one. Signed-off-by: Andrew Jones Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20230918131518.56803-10-ajones@ventanamicro.com Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/cpufeature.h | 1 + arch/riscv/include/asm/csr.h | 1 + arch/riscv/include/asm/hwcap.h | 16 ++++++++++++++++ arch/riscv/kernel/cpufeature.c | 6 ++++++ arch/riscv/kernel/setup.c | 4 ++++ arch/riscv/kernel/smpboot.c | 4 ++++ 6 files changed, 32 insertions(+) diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h index d0345bd659c94..13b7d35648a9c 100644 --- a/arch/riscv/include/asm/cpufeature.h +++ b/arch/riscv/include/asm/cpufeature.h @@ -31,5 +31,6 @@ DECLARE_PER_CPU(long, misaligned_access_speed); extern struct riscv_isainfo hart_isa[NR_CPUS]; void check_unaligned_access(int cpu); +void riscv_user_isa_enable(void); #endif diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h index 777cb8299551c..5fba25db82d2a 100644 --- a/arch/riscv/include/asm/csr.h +++ b/arch/riscv/include/asm/csr.h @@ -275,6 +275,7 @@ #define CSR_SIE 0x104 #define CSR_STVEC 0x105 #define CSR_SCOUNTEREN 0x106 +#define CSR_SENVCFG 0x10a #define CSR_SSCRATCH 0x140 #define CSR_SEPC 0x141 #define CSR_SCAUSE 0x142 diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h index b7b58258f6c7c..31774bcdf1c66 100644 --- a/arch/riscv/include/asm/hwcap.h +++ b/arch/riscv/include/asm/hwcap.h @@ -70,6 +70,7 @@ #ifndef __ASSEMBLY__ #include +#include unsigned long riscv_get_elf_hwcap(void); @@ -137,6 +138,21 @@ riscv_has_extension_unlikely(const unsigned long ext) return true; } +static __always_inline bool riscv_cpu_has_extension_likely(int cpu, const unsigned long ext) +{ + if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && riscv_has_extension_likely(ext)) + return true; + + return __riscv_isa_extension_available(hart_isa[cpu].isa, ext); +} + +static __always_inline bool riscv_cpu_has_extension_unlikely(int cpu, const unsigned long ext) +{ + if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && riscv_has_extension_unlikely(ext)) + return true; + + return __riscv_isa_extension_available(hart_isa[cpu].isa, ext); +} #endif #endif /* _ASM_RISCV_HWCAP_H */ diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index f9ac2717bc7d7..8ad6da03ee348 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -653,6 +653,12 @@ static int check_unaligned_access_boot_cpu(void) arch_initcall(check_unaligned_access_boot_cpu); +void riscv_user_isa_enable(void) +{ + if (riscv_cpu_has_extension_unlikely(smp_processor_id(), RISCV_ISA_EXT_ZICBOZ)) + csr_set(CSR_SENVCFG, ENVCFG_CBZE); +} + #ifdef CONFIG_RISCV_ALTERNATIVE /* * Alternative patch sites consider 48 bits when determining when to patch diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c index e600aab116a40..8fd6c02353d43 100644 --- a/arch/riscv/kernel/setup.c +++ b/arch/riscv/kernel/setup.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -314,10 +315,13 @@ void __init setup_arch(char **cmdline_p) riscv_fill_hwcap(); init_rt_signal_env(); apply_boot_alternatives(); + if (IS_ENABLED(CONFIG_RISCV_ISA_ZICBOM) && riscv_isa_extension_available(NULL, ZICBOM)) riscv_noncoherent_supported(); riscv_set_dma_cache_alignment(); + + riscv_user_isa_enable(); } static int __init topology_init(void) diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c index 1b8da4e40a4d6..d1b0a6fc3adfc 100644 --- a/arch/riscv/kernel/smpboot.c +++ b/arch/riscv/kernel/smpboot.c @@ -25,6 +25,8 @@ #include #include #include + +#include #include #include #include @@ -253,6 +255,8 @@ asmlinkage __visible void smp_callin(void) elf_hwcap &= ~COMPAT_HWCAP_ISA_V; } + riscv_user_isa_enable(); + /* * Remote TLB flushes are ignored while the CPU is offline, so emit * a local TLB flush right now just in case. -- GitLab From 9c7646d5ffd2b8bf720a0b77897f6c5095dfc53b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 18 Sep 2023 15:15:22 +0200 Subject: [PATCH 0060/1451] RISC-V: hwprobe: Expose Zicboz extension and its block size Expose Zicboz through hwprobe and also provide a key to extract its respective block size. Opportunistically add a macro and apply it to current extensions in order to avoid duplicating code. Signed-off-by: Andrew Jones Reviewed-by: Evan Green Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20230918131518.56803-11-ajones@ventanamicro.com Signed-off-by: Palmer Dabbelt --- Documentation/riscv/hwprobe.rst | 6 ++++ arch/riscv/include/asm/hwprobe.h | 2 +- arch/riscv/include/uapi/asm/hwprobe.h | 2 ++ arch/riscv/kernel/sys_riscv.c | 46 +++++++++++++++++++-------- 4 files changed, 41 insertions(+), 15 deletions(-) diff --git a/Documentation/riscv/hwprobe.rst b/Documentation/riscv/hwprobe.rst index a52996b22f75d..7b2384de471f8 100644 --- a/Documentation/riscv/hwprobe.rst +++ b/Documentation/riscv/hwprobe.rst @@ -77,6 +77,9 @@ The following keys are defined: * :c:macro:`RISCV_HWPROBE_EXT_ZBS`: The Zbs extension is supported, as defined in version 1.0 of the Bit-Manipulation ISA extensions. + * :c:macro:`RISCV_HWPROBE_EXT_ZICBOZ`: The Zicboz extension is supported, as + ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs. + * :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: A bitmask that contains performance information about the selected set of processors. @@ -96,3 +99,6 @@ The following keys are defined: * :c:macro:`RISCV_HWPROBE_MISALIGNED_UNSUPPORTED`: Misaligned accesses are not supported at all and will generate a misaligned address fault. + +* :c:macro:`RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE`: An unsigned int which + represents the size of the Zicboz block in bytes. diff --git a/arch/riscv/include/asm/hwprobe.h b/arch/riscv/include/asm/hwprobe.h index 78936f4ff5133..39df8604fea18 100644 --- a/arch/riscv/include/asm/hwprobe.h +++ b/arch/riscv/include/asm/hwprobe.h @@ -8,6 +8,6 @@ #include -#define RISCV_HWPROBE_MAX_KEY 5 +#define RISCV_HWPROBE_MAX_KEY 6 #endif diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h index 006bfb48343dd..86d08a0e617b1 100644 --- a/arch/riscv/include/uapi/asm/hwprobe.h +++ b/arch/riscv/include/uapi/asm/hwprobe.h @@ -29,6 +29,7 @@ struct riscv_hwprobe { #define RISCV_HWPROBE_EXT_ZBA (1 << 3) #define RISCV_HWPROBE_EXT_ZBB (1 << 4) #define RISCV_HWPROBE_EXT_ZBS (1 << 5) +#define RISCV_HWPROBE_EXT_ZICBOZ (1 << 6) #define RISCV_HWPROBE_KEY_CPUPERF_0 5 #define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) #define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0) @@ -36,6 +37,7 @@ struct riscv_hwprobe { #define RISCV_HWPROBE_MISALIGNED_FAST (3 << 0) #define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0) #define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0) +#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6 /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */ #endif diff --git a/arch/riscv/kernel/sys_riscv.c b/arch/riscv/kernel/sys_riscv.c index 473159b5f303a..d7266a9abc661 100644 --- a/arch/riscv/kernel/sys_riscv.c +++ b/arch/riscv/kernel/sys_riscv.c @@ -145,26 +145,38 @@ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair, for_each_cpu(cpu, cpus) { struct riscv_isainfo *isainfo = &hart_isa[cpu]; - if (riscv_isa_extension_available(isainfo->isa, ZBA)) - pair->value |= RISCV_HWPROBE_EXT_ZBA; - else - missing |= RISCV_HWPROBE_EXT_ZBA; - - if (riscv_isa_extension_available(isainfo->isa, ZBB)) - pair->value |= RISCV_HWPROBE_EXT_ZBB; - else - missing |= RISCV_HWPROBE_EXT_ZBB; - - if (riscv_isa_extension_available(isainfo->isa, ZBS)) - pair->value |= RISCV_HWPROBE_EXT_ZBS; - else - missing |= RISCV_HWPROBE_EXT_ZBS; +#define EXT_KEY(ext) \ + do { \ + if (__riscv_isa_extension_available(isainfo->isa, RISCV_ISA_EXT_##ext)) \ + pair->value |= RISCV_HWPROBE_EXT_##ext; \ + else \ + missing |= RISCV_HWPROBE_EXT_##ext; \ + } while (false) + + /* + * Only use EXT_KEY() for extensions which can be exposed to userspace, + * regardless of the kernel's configuration, as no other checks, besides + * presence in the hart_isa bitmap, are made. + */ + EXT_KEY(ZBA); + EXT_KEY(ZBB); + EXT_KEY(ZBS); + EXT_KEY(ZICBOZ); +#undef EXT_KEY } /* Now turn off reporting features if any CPU is missing it. */ pair->value &= ~missing; } +static bool hwprobe_ext0_has(const struct cpumask *cpus, unsigned long ext) +{ + struct riscv_hwprobe pair; + + hwprobe_isa_ext0(&pair, cpus); + return (pair.value & ext); +} + static u64 hwprobe_misaligned(const struct cpumask *cpus) { int cpu; @@ -215,6 +227,12 @@ static void hwprobe_one_pair(struct riscv_hwprobe *pair, pair->value = hwprobe_misaligned(cpus); break; + case RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE: + pair->value = 0; + if (hwprobe_ext0_has(cpus, RISCV_HWPROBE_EXT_ZICBOZ)) + pair->value = riscv_cboz_block_size; + break; + /* * For forward compatibility, unknown keys don't fail the whole * call, but get their element key set to -1 and value set to 0 -- GitLab From fc9fdf2c5ab71e27e64b9e14606b677cc2e45884 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 18 Sep 2023 15:15:23 +0200 Subject: [PATCH 0061/1451] RISC-V: selftests: Statically link hwprobe test Statically linking makes it more convenient to copy the test to a minimal busybox environment. Signed-off-by: Andrew Jones Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20230918131518.56803-12-ajones@ventanamicro.com Signed-off-by: Palmer Dabbelt --- tools/testing/selftests/riscv/hwprobe/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/riscv/hwprobe/Makefile b/tools/testing/selftests/riscv/hwprobe/Makefile index ebdbb3c22e542..5f614c3ba5980 100644 --- a/tools/testing/selftests/riscv/hwprobe/Makefile +++ b/tools/testing/selftests/riscv/hwprobe/Makefile @@ -7,4 +7,4 @@ TEST_GEN_PROGS := hwprobe include ../../lib.mk $(OUTPUT)/hwprobe: hwprobe.c sys_hwprobe.S - $(CC) -o$@ $(CFLAGS) $(LDFLAGS) $^ + $(CC) -static -o$@ $(CFLAGS) $(LDFLAGS) $^ -- GitLab From 2f248e0f8a6aa7199f435d77d94b53cf647e7d7b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 18 Sep 2023 15:15:24 +0200 Subject: [PATCH 0062/1451] RISC-V: selftests: Convert hwprobe test to kselftest API Returning (exiting with) negative exit codes isn't user friendly, because the user must output the exit code with the shell, convert it from its unsigned 8-bit value back to the negative value, and then look up where that comes from in the code (which may be multiple places). Use the kselftests TAP interface, instead. Signed-off-by: Andrew Jones Link: https://lore.kernel.org/r/20230918131518.56803-13-ajones@ventanamicro.com Signed-off-by: Palmer Dabbelt --- .../testing/selftests/riscv/hwprobe/hwprobe.c | 54 +++++++------------ 1 file changed, 20 insertions(+), 34 deletions(-) diff --git a/tools/testing/selftests/riscv/hwprobe/hwprobe.c b/tools/testing/selftests/riscv/hwprobe/hwprobe.c index 09f290a674206..4f15f1f3b4c3c 100644 --- a/tools/testing/selftests/riscv/hwprobe/hwprobe.c +++ b/tools/testing/selftests/riscv/hwprobe/hwprobe.c @@ -2,6 +2,8 @@ #include #include +#include "../../kselftest.h" + /* * Rather than relying on having a new enough libc to define this, just do it * ourselves. This way we don't need to be coupled to a new-enough libc to @@ -16,6 +18,9 @@ int main(int argc, char **argv) unsigned long cpus; long out; + ksft_print_header(); + ksft_set_plan(5); + /* Fake the CPU_SET ops. */ cpus = -1; @@ -25,13 +30,16 @@ int main(int argc, char **argv) */ for (long i = 0; i < 8; i++) pairs[i].key = i; + out = riscv_hwprobe(pairs, 8, 1, &cpus, 0); if (out != 0) - return -1; + ksft_exit_fail_msg("hwprobe() failed with %ld\n", out); + for (long i = 0; i < 4; ++i) { /* Fail if the kernel claims not to recognize a base key. */ if ((i < 4) && (pairs[i].key != i)) - return -2; + ksft_exit_fail_msg("Failed to recognize base key: key != i, " + "key=%ld, i=%ld\n", pairs[i].key, i); if (pairs[i].key != RISCV_HWPROBE_KEY_BASE_BEHAVIOR) continue; @@ -39,52 +47,30 @@ int main(int argc, char **argv) if (pairs[i].value & RISCV_HWPROBE_BASE_BEHAVIOR_IMA) continue; - return -3; + ksft_exit_fail_msg("Unexpected pair: (%ld, %ld)\n", pairs[i].key, pairs[i].value); } - /* - * This should also work with a NULL CPU set, but should not work - * with an improperly supplied CPU set. - */ out = riscv_hwprobe(pairs, 8, 0, 0, 0); - if (out != 0) - return -4; + ksft_test_result(out == 0, "NULL CPU set\n"); out = riscv_hwprobe(pairs, 8, 0, &cpus, 0); - if (out == 0) - return -5; + ksft_test_result(out != 0, "Bad CPU set\n"); out = riscv_hwprobe(pairs, 8, 1, 0, 0); - if (out == 0) - return -6; + ksft_test_result(out != 0, "NULL CPU set with non-zero count\n"); - /* - * Check that keys work by providing one that we know exists, and - * checking to make sure the resultig pair is what we asked for. - */ pairs[0].key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR; out = riscv_hwprobe(pairs, 1, 1, &cpus, 0); - if (out != 0) - return -7; - if (pairs[0].key != RISCV_HWPROBE_KEY_BASE_BEHAVIOR) - return -8; + ksft_test_result(out == 0 && pairs[0].key == RISCV_HWPROBE_KEY_BASE_BEHAVIOR, + "Existing key is maintained\n"); - /* - * Check that an unknown key gets overwritten with -1, - * but doesn't block elements after it. - */ pairs[0].key = 0x5555; pairs[1].key = 1; pairs[1].value = 0xAAAA; out = riscv_hwprobe(pairs, 2, 0, 0, 0); - if (out != 0) - return -9; - - if (pairs[0].key != -1) - return -10; - - if ((pairs[1].key != 1) || (pairs[1].value == 0xAAAA)) - return -11; + ksft_test_result(out == 0 && pairs[0].key == -1 && + pairs[1].key == 1 && pairs[1].value != 0xAAAA, + "Unknown key overwritten with -1 and doesn't block other elements\n"); - return 0; + ksft_finished(); } -- GitLab From a29e2a48afe3549ee34d39cf42343ba3fced09c6 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 18 Sep 2023 15:15:25 +0200 Subject: [PATCH 0063/1451] RISC-V: selftests: Add CBO tests Add hwprobe test for Zicboz and its block size. Also, when Zicboz is present, test that cbo.zero may be issued and works. Additionally provide a command line option that enables testing that the Zicbom instructions cause SIGILL and also that cbo.zero causes SIGILL when Zicboz it's not present. The SIGILL tests require "opt-in" with a command line option because the RISC-V ISA does not require unimplemented standard opcodes to issue illegal-instruction exceptions (but hopefully most platforms do). Pinning the test to a subset of cpus with taskset will also restrict the hwprobe calls to that set. Signed-off-by: Andrew Jones Reviewed-by: Xiao Wang Link: https://lore.kernel.org/r/20230918131518.56803-14-ajones@ventanamicro.com Signed-off-by: Palmer Dabbelt --- .../testing/selftests/riscv/hwprobe/Makefile | 7 +- tools/testing/selftests/riscv/hwprobe/cbo.c | 228 ++++++++++++++++++ .../testing/selftests/riscv/hwprobe/hwprobe.c | 12 +- .../testing/selftests/riscv/hwprobe/hwprobe.h | 15 ++ 4 files changed, 250 insertions(+), 12 deletions(-) create mode 100644 tools/testing/selftests/riscv/hwprobe/cbo.c create mode 100644 tools/testing/selftests/riscv/hwprobe/hwprobe.h diff --git a/tools/testing/selftests/riscv/hwprobe/Makefile b/tools/testing/selftests/riscv/hwprobe/Makefile index 5f614c3ba5980..f224b84591fbf 100644 --- a/tools/testing/selftests/riscv/hwprobe/Makefile +++ b/tools/testing/selftests/riscv/hwprobe/Makefile @@ -2,9 +2,14 @@ # Copyright (C) 2021 ARM Limited # Originally tools/testing/arm64/abi/Makefile -TEST_GEN_PROGS := hwprobe +CFLAGS += -I$(top_srcdir)/tools/include + +TEST_GEN_PROGS := hwprobe cbo include ../../lib.mk $(OUTPUT)/hwprobe: hwprobe.c sys_hwprobe.S $(CC) -static -o$@ $(CFLAGS) $(LDFLAGS) $^ + +$(OUTPUT)/cbo: cbo.c sys_hwprobe.S + $(CC) -static -o$@ $(CFLAGS) $(LDFLAGS) $^ diff --git a/tools/testing/selftests/riscv/hwprobe/cbo.c b/tools/testing/selftests/riscv/hwprobe/cbo.c new file mode 100644 index 0000000000000..50a2cc8aef387 --- /dev/null +++ b/tools/testing/selftests/riscv/hwprobe/cbo.c @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Ventana Micro Systems Inc. + * + * Run with 'taskset -c cbo' to only execute hwprobe on a + * subset of cpus, as well as only executing the tests on those cpus. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hwprobe.h" +#include "../../kselftest.h" + +#define MK_CBO(fn) cpu_to_le32((fn) << 20 | 10 << 15 | 2 << 12 | 0 << 7 | 15) + +static char mem[4096] __aligned(4096) = { [0 ... 4095] = 0xa5 }; + +static bool illegal_insn; + +static void sigill_handler(int sig, siginfo_t *info, void *context) +{ + unsigned long *regs = (unsigned long *)&((ucontext_t *)context)->uc_mcontext; + uint32_t insn = *(uint32_t *)regs[0]; + + assert(insn == MK_CBO(regs[11])); + + illegal_insn = true; + regs[0] += 4; +} + +static void cbo_insn(char *base, int fn) +{ + uint32_t insn = MK_CBO(fn); + + asm volatile( + "mv a0, %0\n" + "li a1, %1\n" + ".4byte %2\n" + : : "r" (base), "i" (fn), "i" (insn) : "a0", "a1", "memory"); +} + +static void cbo_inval(char *base) { cbo_insn(base, 0); } +static void cbo_clean(char *base) { cbo_insn(base, 1); } +static void cbo_flush(char *base) { cbo_insn(base, 2); } +static void cbo_zero(char *base) { cbo_insn(base, 4); } + +static void test_no_zicbom(void *arg) +{ + ksft_print_msg("Testing Zicbom instructions remain privileged\n"); + + illegal_insn = false; + cbo_clean(&mem[0]); + ksft_test_result(illegal_insn, "No cbo.clean\n"); + + illegal_insn = false; + cbo_flush(&mem[0]); + ksft_test_result(illegal_insn, "No cbo.flush\n"); + + illegal_insn = false; + cbo_inval(&mem[0]); + ksft_test_result(illegal_insn, "No cbo.inval\n"); +} + +static void test_no_zicboz(void *arg) +{ + ksft_print_msg("No Zicboz, testing cbo.zero remains privileged\n"); + + illegal_insn = false; + cbo_zero(&mem[0]); + ksft_test_result(illegal_insn, "No cbo.zero\n"); +} + +static bool is_power_of_2(__u64 n) +{ + return n != 0 && (n & (n - 1)) == 0; +} + +static void test_zicboz(void *arg) +{ + struct riscv_hwprobe pair = { + .key = RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE, + }; + cpu_set_t *cpus = (cpu_set_t *)arg; + __u64 block_size; + int i, j; + long rc; + + rc = riscv_hwprobe(&pair, 1, sizeof(cpu_set_t), (unsigned long *)cpus, 0); + block_size = pair.value; + ksft_test_result(rc == 0 && pair.key == RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE && + is_power_of_2(block_size), "Zicboz block size\n"); + ksft_print_msg("Zicboz block size: %ld\n", block_size); + + illegal_insn = false; + cbo_zero(&mem[block_size]); + ksft_test_result(!illegal_insn, "cbo.zero\n"); + + if (illegal_insn || !is_power_of_2(block_size)) { + ksft_test_result_skip("cbo.zero check\n"); + return; + } + + assert(block_size <= 1024); + + for (i = 0; i < 4096 / block_size; ++i) { + if (i % 2) + cbo_zero(&mem[i * block_size]); + } + + for (i = 0; i < 4096 / block_size; ++i) { + char expected = i % 2 ? 0x0 : 0xa5; + + for (j = 0; j < block_size; ++j) { + if (mem[i * block_size + j] != expected) { + ksft_test_result_fail("cbo.zero check\n"); + ksft_print_msg("cbo.zero check: mem[%d] != 0x%x\n", + i * block_size + j, expected); + return; + } + } + } + + ksft_test_result_pass("cbo.zero check\n"); +} + +static void check_no_zicboz_cpus(cpu_set_t *cpus) +{ + struct riscv_hwprobe pair = { + .key = RISCV_HWPROBE_KEY_IMA_EXT_0, + }; + cpu_set_t one_cpu; + int i = 0, c = 0; + long rc; + + while (i++ < CPU_COUNT(cpus)) { + while (!CPU_ISSET(c, cpus)) + ++c; + + CPU_ZERO(&one_cpu); + CPU_SET(c, &one_cpu); + + rc = riscv_hwprobe(&pair, 1, sizeof(cpu_set_t), (unsigned long *)&one_cpu, 0); + assert(rc == 0 && pair.key == RISCV_HWPROBE_KEY_IMA_EXT_0); + + if (pair.value & RISCV_HWPROBE_EXT_ZICBOZ) + ksft_exit_fail_msg("Zicboz is only present on a subset of harts.\n" + "Use taskset to select a set of harts where Zicboz\n" + "presence (present or not) is consistent for each hart\n"); + ++c; + } +} + +enum { + TEST_ZICBOZ, + TEST_NO_ZICBOZ, + TEST_NO_ZICBOM, +}; + +static struct test_info { + bool enabled; + unsigned int nr_tests; + void (*test_fn)(void *arg); +} tests[] = { + [TEST_ZICBOZ] = { .nr_tests = 3, test_zicboz }, + [TEST_NO_ZICBOZ] = { .nr_tests = 1, test_no_zicboz }, + [TEST_NO_ZICBOM] = { .nr_tests = 3, test_no_zicbom }, +}; + +int main(int argc, char **argv) +{ + struct sigaction act = { + .sa_sigaction = &sigill_handler, + .sa_flags = SA_SIGINFO, + }; + struct riscv_hwprobe pair; + unsigned int plan = 0; + cpu_set_t cpus; + long rc; + int i; + + if (argc > 1 && !strcmp(argv[1], "--sigill")) { + rc = sigaction(SIGILL, &act, NULL); + assert(rc == 0); + tests[TEST_NO_ZICBOZ].enabled = true; + tests[TEST_NO_ZICBOM].enabled = true; + } + + rc = sched_getaffinity(0, sizeof(cpu_set_t), &cpus); + assert(rc == 0); + + ksft_print_header(); + + pair.key = RISCV_HWPROBE_KEY_IMA_EXT_0; + rc = riscv_hwprobe(&pair, 1, sizeof(cpu_set_t), (unsigned long *)&cpus, 0); + if (rc < 0) + ksft_exit_fail_msg("hwprobe() failed with %d\n", rc); + assert(rc == 0 && pair.key == RISCV_HWPROBE_KEY_IMA_EXT_0); + + if (pair.value & RISCV_HWPROBE_EXT_ZICBOZ) { + tests[TEST_ZICBOZ].enabled = true; + tests[TEST_NO_ZICBOZ].enabled = false; + } else { + check_no_zicboz_cpus(&cpus); + } + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + plan += tests[i].enabled ? tests[i].nr_tests : 0; + + if (plan == 0) + ksft_print_msg("No tests enabled.\n"); + else + ksft_set_plan(plan); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) { + if (tests[i].enabled) + tests[i].test_fn(&cpus); + } + + ksft_finished(); +} diff --git a/tools/testing/selftests/riscv/hwprobe/hwprobe.c b/tools/testing/selftests/riscv/hwprobe/hwprobe.c index 4f15f1f3b4c3c..c474891df3071 100644 --- a/tools/testing/selftests/riscv/hwprobe/hwprobe.c +++ b/tools/testing/selftests/riscv/hwprobe/hwprobe.c @@ -1,17 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only -#include -#include - +#include "hwprobe.h" #include "../../kselftest.h" -/* - * Rather than relying on having a new enough libc to define this, just do it - * ourselves. This way we don't need to be coupled to a new-enough libc to - * contain the call. - */ -long riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, - size_t cpu_count, unsigned long *cpus, unsigned int flags); - int main(int argc, char **argv) { struct riscv_hwprobe pairs[8]; diff --git a/tools/testing/selftests/riscv/hwprobe/hwprobe.h b/tools/testing/selftests/riscv/hwprobe/hwprobe.h new file mode 100644 index 0000000000000..721b0ce73a569 --- /dev/null +++ b/tools/testing/selftests/riscv/hwprobe/hwprobe.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef SELFTEST_RISCV_HWPROBE_H +#define SELFTEST_RISCV_HWPROBE_H +#include +#include + +/* + * Rather than relying on having a new enough libc to define this, just do it + * ourselves. This way we don't need to be coupled to a new-enough libc to + * contain the call. + */ +long riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, + size_t cpu_count, unsigned long *cpus, unsigned int flags); + +#endif -- GitLab From 34eb78f28e5a8f7fd155776cdcdd052325b47c6e Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 19 Sep 2023 11:23:36 +0200 Subject: [PATCH 0064/1451] remoteproc: mediatek: Refactor single core check and fix retrocompatibility In older devicetrees we had the ChromeOS EC in a node called "cros-ec" instead of the newer "cros-ec-rpmsg", but this driver is now checking only for the latter, breaking compatibility with those. Besides, we can check if the SCP is single or dual core by simply walking through the children of the main SCP node and checking if if there's more than one "mediatek,scp-core" compatible node. Fixes: 1fdbf0cdde98 ("remoteproc: mediatek: Probe SCP cluster on multi-core SCP") Reported-by: "kernelci.org bot" Tested-by: Laura Nao Reviewed-by: Chen-Yu Tsai Tested-by: Chen-Yu Tsai Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230919092336.51007-1-angelogioacchino.delregno@collabora.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/mtk_scp.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index ea227b566c543..a35409eda0cf2 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -1144,29 +1144,25 @@ static int scp_add_multi_core(struct platform_device *pdev, return ret; } -static int scp_is_single_core(struct platform_device *pdev) +static bool scp_is_single_core(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev_of_node(dev); struct device_node *child; + int num_cores = 0; - child = of_get_next_available_child(np, NULL); - if (!child) - return dev_err_probe(dev, -ENODEV, "No child node\n"); + for_each_child_of_node(np, child) + if (of_device_is_compatible(child, "mediatek,scp-core")) + num_cores++; - of_node_put(child); - return of_node_name_eq(child, "cros-ec-rpmsg"); + return num_cores < 2; } static int scp_cluster_init(struct platform_device *pdev, struct mtk_scp_of_cluster *scp_cluster) { int ret; - ret = scp_is_single_core(pdev); - if (ret < 0) - return ret; - - if (ret) + if (scp_is_single_core(pdev)) ret = scp_add_single_core(pdev, scp_cluster); else ret = scp_add_multi_core(pdev, scp_cluster); -- GitLab From 21d9067efc7fe94d2bc6f7c7ce71834d5766bbd8 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 20 Sep 2023 20:07:06 +0200 Subject: [PATCH 0065/1451] gfs2: Get rid of the gfs2_glock_is_held_* helpers Those helpers don't add any clarity and are easy to use wrong. Spell them out to make more obvious what's happening. Signed-off-by: Andreas Gruenbacher --- fs/gfs2/aops.c | 2 +- fs/gfs2/glock.h | 15 --------------- fs/gfs2/inode.c | 2 +- 3 files changed, 2 insertions(+), 17 deletions(-) diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index c26d48355cc27..52fad5bcb0472 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -155,7 +155,7 @@ static int gfs2_jdata_writepage(struct page *page, struct writeback_control *wbc struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); - if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl))) + if (gfs2_assert_withdraw(sdp, ip->i_gl->gl_state == LM_ST_EXCLUSIVE)) goto out; if (folio_test_checked(folio) || current->journal_info) goto out_ignore; diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index c8685ca7d2a26..4daad53f9436c 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -156,21 +156,6 @@ static inline struct gfs2_holder *gfs2_glock_is_locked_by_me(struct gfs2_glock * return gh; } -static inline int gfs2_glock_is_held_excl(struct gfs2_glock *gl) -{ - return gl->gl_state == LM_ST_EXCLUSIVE; -} - -static inline int gfs2_glock_is_held_dfrd(struct gfs2_glock *gl) -{ - return gl->gl_state == LM_ST_DEFERRED; -} - -static inline int gfs2_glock_is_held_shrd(struct gfs2_glock *gl) -{ - return gl->gl_state == LM_ST_SHARED; -} - static inline struct address_space *gfs2_glock2aspace(struct gfs2_glock *gl) { if (gl->gl_ops->go_flags & GLOF_ASPACE) { diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 0eac045079047..2880d6ca19e10 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -2153,7 +2153,7 @@ static int gfs2_update_time(struct inode *inode, int flags) int error; gh = gfs2_glock_is_locked_by_me(gl); - if (gh && !gfs2_glock_is_held_excl(gl)) { + if (gh && gl->gl_state != LM_ST_EXCLUSIVE) { gfs2_glock_dq(gh); gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, gh); error = gfs2_glock_nq(gh); -- GitLab From 089f4eb003dc2265036aac99c02aa99d6b5c4ac7 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 20 Sep 2023 18:17:39 +0200 Subject: [PATCH 0066/1451] gfs2: Don't update inode timestamps for direct writes During direct reads and writes, the caller is holding the inode glock in deferred mode, which doesn't allow metadata updates. However, a previous change caused callers to update the inode modification time before carrying out direct writes, which caused the inode glock to be converted to exclusive mode for the timestamp update, only to be immediately converted back to deferred mode for the direct write. This locks out other direct readers and writers and wreaks havoc on performance. Fix that by reverting to not updating the inode modification time for direct writes. Signed-off-by: Andreas Gruenbacher --- fs/gfs2/file.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index f2700477a3001..5bc103b031e29 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -1120,14 +1120,16 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (ret) goto out_unlock; - ret = file_update_time(file); - if (ret) - goto out_unlock; - if (iocb->ki_flags & IOCB_DIRECT) { struct address_space *mapping = file->f_mapping; ssize_t buffered, ret2; + /* + * Note that under direct I/O, we don't allow and inode + * timestamp updates, so we're not calling file_update_time() + * here. + */ + ret = gfs2_file_direct_write(iocb, from, &gh); if (ret < 0 || !iov_iter_count(from)) goto out_unlock; @@ -1154,6 +1156,10 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (!ret || ret2 > 0) ret += ret2; } else { + ret = file_update_time(file); + if (ret) + goto out_unlock; + ret = gfs2_file_buffered_write(iocb, from, &gh); if (likely(ret > 0)) ret = generic_write_sync(iocb, ret); -- GitLab From 18965fcfc5d0762e6e1bcd5ab48172ffce9433d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:38 +0200 Subject: [PATCH 0067/1451] Input: adp5520-keys - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-2-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/adp5520-keys.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/keyboard/adp5520-keys.c b/drivers/input/keyboard/adp5520-keys.c index 7851ffd678a8f..10c248f0c1fcd 100644 --- a/drivers/input/keyboard/adp5520-keys.c +++ b/drivers/input/keyboard/adp5520-keys.c @@ -168,14 +168,12 @@ static int adp5520_keys_probe(struct platform_device *pdev) return 0; } -static int adp5520_keys_remove(struct platform_device *pdev) +static void adp5520_keys_remove(struct platform_device *pdev) { struct adp5520_keys *dev = platform_get_drvdata(pdev); adp5520_unregister_notifier(dev->master, &dev->notifier, ADP5520_KP_IEN | ADP5520_KR_IEN); - - return 0; } static struct platform_driver adp5520_keys_driver = { @@ -183,7 +181,7 @@ static struct platform_driver adp5520_keys_driver = { .name = "adp5520-keys", }, .probe = adp5520_keys_probe, - .remove = adp5520_keys_remove, + .remove_new = adp5520_keys_remove, }; module_platform_driver(adp5520_keys_driver); -- GitLab From 63ef64cb6453740ecb53acbbfdfe5725adcd2a8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:39 +0200 Subject: [PATCH 0068/1451] Input: cros_ec_keyb - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20230920125829.1478827-3-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/cros_ec_keyb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index 313b7a69dd692..30678a34cf647 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c @@ -743,14 +743,12 @@ static int cros_ec_keyb_probe(struct platform_device *pdev) return 0; } -static int cros_ec_keyb_remove(struct platform_device *pdev) +static void cros_ec_keyb_remove(struct platform_device *pdev) { struct cros_ec_keyb *ckdev = dev_get_drvdata(&pdev->dev); blocking_notifier_chain_unregister(&ckdev->ec->event_notifier, &ckdev->notifier); - - return 0; } #ifdef CONFIG_ACPI @@ -774,7 +772,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(cros_ec_keyb_pm_ops, NULL, cros_ec_keyb_resume); static struct platform_driver cros_ec_keyb_driver = { .probe = cros_ec_keyb_probe, - .remove = cros_ec_keyb_remove, + .remove_new = cros_ec_keyb_remove, .driver = { .name = "cros-ec-keyb", .dev_groups = cros_ec_keyb_groups, -- GitLab From d9ee4119a83cab3184b2bd8cc2804bdcb043fc3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:40 +0200 Subject: [PATCH 0069/1451] Input: ep93xx_keypad - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-4-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/ep93xx_keypad.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c index 55075addcac26..6b811d6bf6258 100644 --- a/drivers/input/keyboard/ep93xx_keypad.c +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -308,11 +308,9 @@ static int ep93xx_keypad_probe(struct platform_device *pdev) return 0; } -static int ep93xx_keypad_remove(struct platform_device *pdev) +static void ep93xx_keypad_remove(struct platform_device *pdev) { dev_pm_clear_wake_irq(&pdev->dev); - - return 0; } static struct platform_driver ep93xx_keypad_driver = { @@ -321,7 +319,7 @@ static struct platform_driver ep93xx_keypad_driver = { .pm = pm_sleep_ptr(&ep93xx_keypad_pm_ops), }, .probe = ep93xx_keypad_probe, - .remove = ep93xx_keypad_remove, + .remove_new = ep93xx_keypad_remove, }; module_platform_driver(ep93xx_keypad_driver); -- GitLab From 0080c3c43dbafb819c91a5fc6a782834badc6527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:41 +0200 Subject: [PATCH 0070/1451] Input: iqs62x-keys - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Jeff LaBundy Link: https://lore.kernel.org/r/20230920125829.1478827-5-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/iqs62x-keys.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/keyboard/iqs62x-keys.c b/drivers/input/keyboard/iqs62x-keys.c index 02ceebad7bdaa..688d61244b5fd 100644 --- a/drivers/input/keyboard/iqs62x-keys.c +++ b/drivers/input/keyboard/iqs62x-keys.c @@ -310,7 +310,7 @@ static int iqs62x_keys_probe(struct platform_device *pdev) return ret; } -static int iqs62x_keys_remove(struct platform_device *pdev) +static void iqs62x_keys_remove(struct platform_device *pdev) { struct iqs62x_keys_private *iqs62x_keys = platform_get_drvdata(pdev); int ret; @@ -319,8 +319,6 @@ static int iqs62x_keys_remove(struct platform_device *pdev) &iqs62x_keys->notifier); if (ret) dev_err(&pdev->dev, "Failed to unregister notifier: %d\n", ret); - - return 0; } static struct platform_driver iqs62x_keys_platform_driver = { @@ -328,7 +326,7 @@ static struct platform_driver iqs62x_keys_platform_driver = { .name = "iqs62x-keys", }, .probe = iqs62x_keys_probe, - .remove = iqs62x_keys_remove, + .remove_new = iqs62x_keys_remove, }; module_platform_driver(iqs62x_keys_platform_driver); -- GitLab From af90388a598d39584283c18e4047124fee8f1801 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:42 +0200 Subject: [PATCH 0071/1451] Input: matrix_keypad - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-6-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/matrix_keypad.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index a1b037891af25..50fa764c82d2b 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -549,15 +549,13 @@ static int matrix_keypad_probe(struct platform_device *pdev) return err; } -static int matrix_keypad_remove(struct platform_device *pdev) +static void matrix_keypad_remove(struct platform_device *pdev) { struct matrix_keypad *keypad = platform_get_drvdata(pdev); matrix_keypad_free_gpio(keypad); input_unregister_device(keypad->input_dev); kfree(keypad); - - return 0; } #ifdef CONFIG_OF @@ -570,7 +568,7 @@ MODULE_DEVICE_TABLE(of, matrix_keypad_dt_match); static struct platform_driver matrix_keypad_driver = { .probe = matrix_keypad_probe, - .remove = matrix_keypad_remove, + .remove_new = matrix_keypad_remove, .driver = { .name = "matrix-keypad", .pm = pm_sleep_ptr(&matrix_keypad_pm_ops), -- GitLab From d93f3feb443939d27a2dc664267d29d42c4a6955 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:43 +0200 Subject: [PATCH 0072/1451] Input: omap-keypad - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-7-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/omap-keypad.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index 24440b4986457..454fb86756573 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -287,7 +287,7 @@ static int omap_kp_probe(struct platform_device *pdev) return -EINVAL; } -static int omap_kp_remove(struct platform_device *pdev) +static void omap_kp_remove(struct platform_device *pdev) { struct omap_kp *omap_kp = platform_get_drvdata(pdev); @@ -303,13 +303,11 @@ static int omap_kp_remove(struct platform_device *pdev) input_unregister_device(omap_kp->input); kfree(omap_kp); - - return 0; } static struct platform_driver omap_kp_driver = { .probe = omap_kp_probe, - .remove = omap_kp_remove, + .remove_new = omap_kp_remove, .driver = { .name = "omap-keypad", }, -- GitLab From ec4c61a69ddc8b7f486f81f356f7cd29699b8662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:44 +0200 Subject: [PATCH 0073/1451] Input: omap4-keypad - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-8-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/omap4-keypad.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index 773e55eed88b1..d3f8688fdd9c3 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -461,11 +461,9 @@ static int omap4_keypad_probe(struct platform_device *pdev) return 0; } -static int omap4_keypad_remove(struct platform_device *pdev) +static void omap4_keypad_remove(struct platform_device *pdev) { dev_pm_clear_wake_irq(&pdev->dev); - - return 0; } static const struct of_device_id omap_keypad_dt_match[] = { @@ -476,7 +474,7 @@ MODULE_DEVICE_TABLE(of, omap_keypad_dt_match); static struct platform_driver omap4_keypad_driver = { .probe = omap4_keypad_probe, - .remove = omap4_keypad_remove, + .remove_new = omap4_keypad_remove, .driver = { .name = "omap4-keypad", .of_match_table = omap_keypad_dt_match, -- GitLab From 4e26858958e41f520a607df258a0c709f0c9a5ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:45 +0200 Subject: [PATCH 0074/1451] Input: samsung-keypad - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-9-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/samsung-keypad.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index d85dd24892934..e212eff7687c0 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c @@ -444,7 +444,7 @@ static int samsung_keypad_probe(struct platform_device *pdev) return error; } -static int samsung_keypad_remove(struct platform_device *pdev) +static void samsung_keypad_remove(struct platform_device *pdev) { struct samsung_keypad *keypad = platform_get_drvdata(pdev); @@ -453,8 +453,6 @@ static int samsung_keypad_remove(struct platform_device *pdev) input_unregister_device(keypad->input_dev); clk_unprepare(keypad->clk); - - return 0; } static int samsung_keypad_runtime_suspend(struct device *dev) @@ -589,7 +587,7 @@ MODULE_DEVICE_TABLE(platform, samsung_keypad_driver_ids); static struct platform_driver samsung_keypad_driver = { .probe = samsung_keypad_probe, - .remove = samsung_keypad_remove, + .remove_new = samsung_keypad_remove, .driver = { .name = "samsung-keypad", .of_match_table = of_match_ptr(samsung_keypad_dt_match), -- GitLab From e340089d76f49a462471507aebf1efffeeca65c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:46 +0200 Subject: [PATCH 0075/1451] Input: sh_keysc - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-10-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/sh_keysc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index 2c00320f739fc..4ea4fd25c5d20 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -265,7 +265,7 @@ static int sh_keysc_probe(struct platform_device *pdev) return error; } -static int sh_keysc_remove(struct platform_device *pdev) +static void sh_keysc_remove(struct platform_device *pdev) { struct sh_keysc_priv *priv = platform_get_drvdata(pdev); @@ -279,8 +279,6 @@ static int sh_keysc_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); kfree(priv); - - return 0; } static int sh_keysc_suspend(struct device *dev) @@ -321,7 +319,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(sh_keysc_dev_pm_ops, static struct platform_driver sh_keysc_device_driver = { .probe = sh_keysc_probe, - .remove = sh_keysc_remove, + .remove_new = sh_keysc_remove, .driver = { .name = "sh_keysc", .pm = pm_sleep_ptr(&sh_keysc_dev_pm_ops), -- GitLab From dc20ae18d1a6eb94c8311c701bc6846112bd95d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:47 +0200 Subject: [PATCH 0076/1451] Input: spear-keyboard - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-11-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/spear-keyboard.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c index a50fa9915381f..557d00a667cea 100644 --- a/drivers/input/keyboard/spear-keyboard.c +++ b/drivers/input/keyboard/spear-keyboard.c @@ -272,14 +272,12 @@ static int spear_kbd_probe(struct platform_device *pdev) return 0; } -static int spear_kbd_remove(struct platform_device *pdev) +static void spear_kbd_remove(struct platform_device *pdev) { struct spear_kbd *kbd = platform_get_drvdata(pdev); input_unregister_device(kbd->input); clk_unprepare(kbd->clk); - - return 0; } static int spear_kbd_suspend(struct device *dev) @@ -375,7 +373,7 @@ MODULE_DEVICE_TABLE(of, spear_kbd_id_table); static struct platform_driver spear_kbd_driver = { .probe = spear_kbd_probe, - .remove = spear_kbd_remove, + .remove_new = spear_kbd_remove, .driver = { .name = "keyboard", .pm = pm_sleep_ptr(&spear_kbd_pm_ops), -- GitLab From 00e0df61ee6a44fdd82aa871cdaa8284e4fbbbb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:48 +0200 Subject: [PATCH 0077/1451] Input: stmpe-keypad - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-12-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/stmpe-keypad.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c index 2c6c53290cc0f..2013c0afd0c3a 100644 --- a/drivers/input/keyboard/stmpe-keypad.c +++ b/drivers/input/keyboard/stmpe-keypad.c @@ -404,20 +404,18 @@ static int stmpe_keypad_probe(struct platform_device *pdev) return 0; } -static int stmpe_keypad_remove(struct platform_device *pdev) +static void stmpe_keypad_remove(struct platform_device *pdev) { struct stmpe_keypad *keypad = platform_get_drvdata(pdev); stmpe_disable(keypad->stmpe, STMPE_BLOCK_KEYPAD); - - return 0; } static struct platform_driver stmpe_keypad_driver = { .driver.name = "stmpe-keypad", .driver.owner = THIS_MODULE, .probe = stmpe_keypad_probe, - .remove = stmpe_keypad_remove, + .remove_new = stmpe_keypad_remove, }; module_platform_driver(stmpe_keypad_driver); -- GitLab From 3e2ccfd93c4a2c274900537595105589cb9882ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:49 +0200 Subject: [PATCH 0078/1451] Input: 88pm80x_onkey - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-13-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/misc/88pm80x_onkey.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/input/misc/88pm80x_onkey.c b/drivers/input/misc/88pm80x_onkey.c index 51c8a326fd068..31f0702c3d01e 100644 --- a/drivers/input/misc/88pm80x_onkey.c +++ b/drivers/input/misc/88pm80x_onkey.c @@ -138,14 +138,13 @@ static int pm80x_onkey_probe(struct platform_device *pdev) return err; } -static int pm80x_onkey_remove(struct platform_device *pdev) +static void pm80x_onkey_remove(struct platform_device *pdev) { struct pm80x_onkey_info *info = platform_get_drvdata(pdev); pm80x_free_irq(info->pm80x, info->irq, info); input_unregister_device(info->idev); kfree(info); - return 0; } static struct platform_driver pm80x_onkey_driver = { @@ -154,7 +153,7 @@ static struct platform_driver pm80x_onkey_driver = { .pm = &pm80x_onkey_pm_ops, }, .probe = pm80x_onkey_probe, - .remove = pm80x_onkey_remove, + .remove_new = pm80x_onkey_remove, }; module_platform_driver(pm80x_onkey_driver); -- GitLab From d6bcf6cdd041050d3f5713f06ded31ef8afe143f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:50 +0200 Subject: [PATCH 0079/1451] Input: da9052_onkey - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-14-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/misc/da9052_onkey.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/misc/da9052_onkey.c b/drivers/input/misc/da9052_onkey.c index 6d1152850a6d8..7a1122e1efb9c 100644 --- a/drivers/input/misc/da9052_onkey.c +++ b/drivers/input/misc/da9052_onkey.c @@ -127,7 +127,7 @@ static int da9052_onkey_probe(struct platform_device *pdev) return error; } -static int da9052_onkey_remove(struct platform_device *pdev) +static void da9052_onkey_remove(struct platform_device *pdev) { struct da9052_onkey *onkey = platform_get_drvdata(pdev); @@ -136,13 +136,11 @@ static int da9052_onkey_remove(struct platform_device *pdev) input_unregister_device(onkey->input); kfree(onkey); - - return 0; } static struct platform_driver da9052_onkey_driver = { .probe = da9052_onkey_probe, - .remove = da9052_onkey_remove, + .remove_new = da9052_onkey_remove, .driver = { .name = "da9052-onkey", }, -- GitLab From d8584e00d989ad2eee3fe2dc09ce2a1a31f060d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:51 +0200 Subject: [PATCH 0080/1451] Input: da9055_onkey - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-15-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/misc/da9055_onkey.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/misc/da9055_onkey.c b/drivers/input/misc/da9055_onkey.c index 7a0d3a1d503cf..871812f1b398e 100644 --- a/drivers/input/misc/da9055_onkey.c +++ b/drivers/input/misc/da9055_onkey.c @@ -132,7 +132,7 @@ static int da9055_onkey_probe(struct platform_device *pdev) return err; } -static int da9055_onkey_remove(struct platform_device *pdev) +static void da9055_onkey_remove(struct platform_device *pdev) { struct da9055_onkey *onkey = platform_get_drvdata(pdev); int irq = platform_get_irq_byname(pdev, "ONKEY"); @@ -141,13 +141,11 @@ static int da9055_onkey_remove(struct platform_device *pdev) free_irq(irq, onkey); cancel_delayed_work_sync(&onkey->work); input_unregister_device(onkey->input); - - return 0; } static struct platform_driver da9055_onkey_driver = { .probe = da9055_onkey_probe, - .remove = da9055_onkey_remove, + .remove_new = da9055_onkey_remove, .driver = { .name = "da9055-onkey", }, -- GitLab From 48309b52b175586a9eb5a655f7ea04bb21c8a295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:52 +0200 Subject: [PATCH 0081/1451] Input: ideapad_slidebar - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-16-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/misc/ideapad_slidebar.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/misc/ideapad_slidebar.c b/drivers/input/misc/ideapad_slidebar.c index 68f1c584da056..fa4e7f67d7136 100644 --- a/drivers/input/misc/ideapad_slidebar.c +++ b/drivers/input/misc/ideapad_slidebar.c @@ -256,20 +256,18 @@ static int __init ideapad_probe(struct platform_device* pdev) return err; } -static int ideapad_remove(struct platform_device *pdev) +static void ideapad_remove(struct platform_device *pdev) { i8042_remove_filter(slidebar_i8042_filter); input_unregister_device(slidebar_input_dev); release_region(IDEAPAD_BASE, 3); - - return 0; } static struct platform_driver slidebar_drv = { .driver = { .name = "ideapad_slidebar", }, - .remove = ideapad_remove, + .remove_new = ideapad_remove, }; static int __init ideapad_dmi_check(const struct dmi_system_id *id) -- GitLab From 6d3a5b825496785bf3fc6872e49a9f8443b0d66b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:53 +0200 Subject: [PATCH 0082/1451] Input: m68kspkr - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-17-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/misc/m68kspkr.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c index 25fcf1467151b..3fe0a85c45e00 100644 --- a/drivers/input/misc/m68kspkr.c +++ b/drivers/input/misc/m68kspkr.c @@ -75,15 +75,13 @@ static int m68kspkr_probe(struct platform_device *dev) return 0; } -static int m68kspkr_remove(struct platform_device *dev) +static void m68kspkr_remove(struct platform_device *dev) { struct input_dev *input_dev = platform_get_drvdata(dev); input_unregister_device(input_dev); /* turn off the speaker */ m68kspkr_event(NULL, EV_SND, SND_BELL, 0); - - return 0; } static void m68kspkr_shutdown(struct platform_device *dev) @@ -97,7 +95,7 @@ static struct platform_driver m68kspkr_platform_driver = { .name = "m68kspkr", }, .probe = m68kspkr_probe, - .remove = m68kspkr_remove, + .remove_new = m68kspkr_remove, .shutdown = m68kspkr_shutdown, }; -- GitLab From 3254392ead69ba6b063b3a3871f69c6bf4bb5ccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:54 +0200 Subject: [PATCH 0083/1451] Input: max8997_haptic - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-18-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/misc/max8997_haptic.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/misc/max8997_haptic.c b/drivers/input/misc/max8997_haptic.c index c4dff476d4796..8861a67be5754 100644 --- a/drivers/input/misc/max8997_haptic.c +++ b/drivers/input/misc/max8997_haptic.c @@ -351,7 +351,7 @@ static int max8997_haptic_probe(struct platform_device *pdev) return error; } -static int max8997_haptic_remove(struct platform_device *pdev) +static void max8997_haptic_remove(struct platform_device *pdev) { struct max8997_haptic *chip = platform_get_drvdata(pdev); @@ -362,8 +362,6 @@ static int max8997_haptic_remove(struct platform_device *pdev) pwm_put(chip->pwm); kfree(chip); - - return 0; } static int max8997_haptic_suspend(struct device *dev) @@ -391,7 +389,7 @@ static struct platform_driver max8997_haptic_driver = { .pm = pm_sleep_ptr(&max8997_haptic_pm_ops), }, .probe = max8997_haptic_probe, - .remove = max8997_haptic_remove, + .remove_new = max8997_haptic_remove, .id_table = max8997_haptic_id, }; module_platform_driver(max8997_haptic_driver); -- GitLab From 9b6619667e9ecc771d8d6379311793d8823dad70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:55 +0200 Subject: [PATCH 0084/1451] Input: mc13783-pwrbutton - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-19-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/misc/mc13783-pwrbutton.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c index 0636eee4bb6ce..1c8c939638f6c 100644 --- a/drivers/input/misc/mc13783-pwrbutton.c +++ b/drivers/input/misc/mc13783-pwrbutton.c @@ -229,7 +229,7 @@ static int mc13783_pwrbutton_probe(struct platform_device *pdev) return err; } -static int mc13783_pwrbutton_remove(struct platform_device *pdev) +static void mc13783_pwrbutton_remove(struct platform_device *pdev) { struct mc13783_pwrb *priv = platform_get_drvdata(pdev); const struct mc13xxx_buttons_platform_data *pdata; @@ -249,13 +249,11 @@ static int mc13783_pwrbutton_remove(struct platform_device *pdev) input_unregister_device(priv->pwr); kfree(priv); - - return 0; } static struct platform_driver mc13783_pwrbutton_driver = { .probe = mc13783_pwrbutton_probe, - .remove = mc13783_pwrbutton_remove, + .remove_new = mc13783_pwrbutton_remove, .driver = { .name = "mc13783-pwrbutton", }, -- GitLab From 7db7e7ef75b2658a2a31b69ca68d9e3b5c51702c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:56 +0200 Subject: [PATCH 0085/1451] Input: palmas-pwrbutton - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-20-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/misc/palmas-pwrbutton.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/misc/palmas-pwrbutton.c b/drivers/input/misc/palmas-pwrbutton.c index 7e361727b0d98..06d5972e8e84d 100644 --- a/drivers/input/misc/palmas-pwrbutton.c +++ b/drivers/input/misc/palmas-pwrbutton.c @@ -245,7 +245,7 @@ static int palmas_pwron_probe(struct platform_device *pdev) * * Return: 0 */ -static int palmas_pwron_remove(struct platform_device *pdev) +static void palmas_pwron_remove(struct platform_device *pdev) { struct palmas_pwron *pwron = platform_get_drvdata(pdev); @@ -254,8 +254,6 @@ static int palmas_pwron_remove(struct platform_device *pdev) input_unregister_device(pwron->input_dev); kfree(pwron); - - return 0; } /** @@ -312,7 +310,7 @@ MODULE_DEVICE_TABLE(of, of_palmas_pwr_match); static struct platform_driver palmas_pwron_driver = { .probe = palmas_pwron_probe, - .remove = palmas_pwron_remove, + .remove_new = palmas_pwron_remove, .driver = { .name = "palmas_pwrbutton", .of_match_table = of_match_ptr(of_palmas_pwr_match), -- GitLab From 3757a5fd11ed595b87a39f0db9780cf4c1149564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:57 +0200 Subject: [PATCH 0086/1451] Input: pcap_keys - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-21-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/misc/pcap_keys.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/misc/pcap_keys.c b/drivers/input/misc/pcap_keys.c index b5a53636d7e2e..8a7e9ada59526 100644 --- a/drivers/input/misc/pcap_keys.c +++ b/drivers/input/misc/pcap_keys.c @@ -99,7 +99,7 @@ static int pcap_keys_probe(struct platform_device *pdev) return err; } -static int pcap_keys_remove(struct platform_device *pdev) +static void pcap_keys_remove(struct platform_device *pdev) { struct pcap_keys *pcap_keys = platform_get_drvdata(pdev); @@ -108,13 +108,11 @@ static int pcap_keys_remove(struct platform_device *pdev) input_unregister_device(pcap_keys->input); kfree(pcap_keys); - - return 0; } static struct platform_driver pcap_keys_device_driver = { .probe = pcap_keys_probe, - .remove = pcap_keys_remove, + .remove_new = pcap_keys_remove, .driver = { .name = "pcap-keys", } -- GitLab From 3b87328b0179d13a5e44736fa11ed44abcc30409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:58 +0200 Subject: [PATCH 0087/1451] Input: pcf50633-input - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-22-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/misc/pcf50633-input.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/misc/pcf50633-input.c b/drivers/input/misc/pcf50633-input.c index 4c60c70c4c102..c5c5fe236c182 100644 --- a/drivers/input/misc/pcf50633-input.c +++ b/drivers/input/misc/pcf50633-input.c @@ -87,7 +87,7 @@ static int pcf50633_input_probe(struct platform_device *pdev) return 0; } -static int pcf50633_input_remove(struct platform_device *pdev) +static void pcf50633_input_remove(struct platform_device *pdev) { struct pcf50633_input *input = platform_get_drvdata(pdev); @@ -96,8 +96,6 @@ static int pcf50633_input_remove(struct platform_device *pdev) input_unregister_device(input->input_dev); kfree(input); - - return 0; } static struct platform_driver pcf50633_input_driver = { @@ -105,7 +103,7 @@ static struct platform_driver pcf50633_input_driver = { .name = "pcf50633-input", }, .probe = pcf50633_input_probe, - .remove = pcf50633_input_remove, + .remove_new = pcf50633_input_remove, }; module_platform_driver(pcf50633_input_driver); -- GitLab From 5cd345ec1cf1350089bf02c66f5cd473c0a5a218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:57:59 +0200 Subject: [PATCH 0088/1451] Input: pcspkr - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-23-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/misc/pcspkr.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 9c666b2f14fef..897854fd245f1 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -95,15 +95,13 @@ static int pcspkr_probe(struct platform_device *dev) return 0; } -static int pcspkr_remove(struct platform_device *dev) +static void pcspkr_remove(struct platform_device *dev) { struct input_dev *pcspkr_dev = platform_get_drvdata(dev); input_unregister_device(pcspkr_dev); /* turn off the speaker */ pcspkr_event(NULL, EV_SND, SND_BELL, 0); - - return 0; } static int pcspkr_suspend(struct device *dev) @@ -129,7 +127,7 @@ static struct platform_driver pcspkr_platform_driver = { .pm = &pcspkr_pm_ops, }, .probe = pcspkr_probe, - .remove = pcspkr_remove, + .remove_new = pcspkr_remove, .shutdown = pcspkr_shutdown, }; module_platform_driver(pcspkr_platform_driver); -- GitLab From a72aa189b2df3508c2fcbe41eec96530ed830e50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:00 +0200 Subject: [PATCH 0089/1451] Input: pm8941-pwrkey - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230920125829.1478827-24-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/misc/pm8941-pwrkey.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/misc/pm8941-pwrkey.c b/drivers/input/misc/pm8941-pwrkey.c index ba747c5b2b5fc..bab710023d8f1 100644 --- a/drivers/input/misc/pm8941-pwrkey.c +++ b/drivers/input/misc/pm8941-pwrkey.c @@ -408,14 +408,12 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev) return 0; } -static int pm8941_pwrkey_remove(struct platform_device *pdev) +static void pm8941_pwrkey_remove(struct platform_device *pdev) { struct pm8941_pwrkey *pwrkey = platform_get_drvdata(pdev); if (pwrkey->data->supports_ps_hold_poff_config) unregister_reboot_notifier(&pwrkey->reboot_notifier); - - return 0; } static const struct pm8941_data pwrkey_data = { @@ -467,7 +465,7 @@ MODULE_DEVICE_TABLE(of, pm8941_pwr_key_id_table); static struct platform_driver pm8941_pwrkey_driver = { .probe = pm8941_pwrkey_probe, - .remove = pm8941_pwrkey_remove, + .remove_new = pm8941_pwrkey_remove, .driver = { .name = "pm8941-pwrkey", .pm = pm_sleep_ptr(&pm8941_pwr_key_pm_ops), -- GitLab From 2c4fd21f4a6ffb0c8c2632470b602c0dde8ff20f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:01 +0200 Subject: [PATCH 0090/1451] Input: soc_button_array - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-25-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/misc/soc_button_array.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c index e79f5497948b8..08bcee3d6bcca 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -411,7 +411,7 @@ static struct soc_button_info *soc_button_get_button_info(struct device *dev) return button_info; } -static int soc_button_remove(struct platform_device *pdev) +static void soc_button_remove(struct platform_device *pdev) { struct soc_button_data *priv = platform_get_drvdata(pdev); @@ -420,8 +420,6 @@ static int soc_button_remove(struct platform_device *pdev) for (i = 0; i < BUTTON_TYPES; i++) if (priv->children[i]) platform_device_unregister(priv->children[i]); - - return 0; } static int soc_button_probe(struct platform_device *pdev) @@ -609,7 +607,7 @@ MODULE_DEVICE_TABLE(acpi, soc_button_acpi_match); static struct platform_driver soc_button_driver = { .probe = soc_button_probe, - .remove = soc_button_remove, + .remove_new = soc_button_remove, .driver = { .name = KBUILD_MODNAME, .acpi_match_table = ACPI_PTR(soc_button_acpi_match), -- GitLab From c55fb9780590b8612ef4338441687e6d2aff8c36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:02 +0200 Subject: [PATCH 0091/1451] Input: sparcspkr - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-26-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/misc/sparcspkr.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index e5dd84725c6e7..20020cbc0752b 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -231,7 +231,7 @@ static int bbc_beep_probe(struct platform_device *op) return err; } -static int bbc_remove(struct platform_device *op) +static void bbc_remove(struct platform_device *op) { struct sparcspkr_state *state = platform_get_drvdata(op); struct input_dev *input_dev = state->input_dev; @@ -245,8 +245,6 @@ static int bbc_remove(struct platform_device *op) of_iounmap(&op->resource[0], info->regs, 6); kfree(state); - - return 0; } static const struct of_device_id bbc_beep_match[] = { @@ -264,7 +262,7 @@ static struct platform_driver bbc_beep_driver = { .of_match_table = bbc_beep_match, }, .probe = bbc_beep_probe, - .remove = bbc_remove, + .remove_new = bbc_remove, .shutdown = sparcspkr_shutdown, }; @@ -310,7 +308,7 @@ static int grover_beep_probe(struct platform_device *op) return err; } -static int grover_remove(struct platform_device *op) +static void grover_remove(struct platform_device *op) { struct sparcspkr_state *state = platform_get_drvdata(op); struct grover_beep_info *info = &state->u.grover; @@ -325,8 +323,6 @@ static int grover_remove(struct platform_device *op) of_iounmap(&op->resource[2], info->freq_regs, 2); kfree(state); - - return 0; } static const struct of_device_id grover_beep_match[] = { @@ -344,7 +340,7 @@ static struct platform_driver grover_beep_driver = { .of_match_table = grover_beep_match, }, .probe = grover_beep_probe, - .remove = grover_remove, + .remove_new = grover_remove, .shutdown = sparcspkr_shutdown, }; -- GitLab From ad43716068130dd22d14dc5223f5f5675d96fd12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:03 +0200 Subject: [PATCH 0092/1451] Input: wistron_btns - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-27-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/misc/wistron_btns.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 111cb70cde465..5c4956678cd0a 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -1286,13 +1286,11 @@ static int wistron_probe(struct platform_device *dev) return 0; } -static int wistron_remove(struct platform_device *dev) +static void wistron_remove(struct platform_device *dev) { wistron_led_remove(); input_unregister_device(wistron_idev); bios_detach(); - - return 0; } static int wistron_suspend(struct device *dev) @@ -1336,7 +1334,7 @@ static struct platform_driver wistron_driver = { .pm = pm_sleep_ptr(&wistron_pm_ops), }, .probe = wistron_probe, - .remove = wistron_remove, + .remove_new = wistron_remove, }; static int __init wb_module_init(void) -- GitLab From ee3d5597133c03c7c200f63c51534c2ada24b8fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:04 +0200 Subject: [PATCH 0093/1451] Input: wm831x-on - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20230920125829.1478827-28-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/misc/wm831x-on.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/misc/wm831x-on.c b/drivers/input/misc/wm831x-on.c index a42fe041b73c6..e4a06c73b72d9 100644 --- a/drivers/input/misc/wm831x-on.c +++ b/drivers/input/misc/wm831x-on.c @@ -123,20 +123,18 @@ static int wm831x_on_probe(struct platform_device *pdev) return ret; } -static int wm831x_on_remove(struct platform_device *pdev) +static void wm831x_on_remove(struct platform_device *pdev) { struct wm831x_on *wm831x_on = platform_get_drvdata(pdev); int irq = platform_get_irq(pdev, 0); free_irq(irq, wm831x_on); cancel_delayed_work_sync(&wm831x_on->work); - - return 0; } static struct platform_driver wm831x_on_driver = { .probe = wm831x_on_probe, - .remove = wm831x_on_remove, + .remove_new = wm831x_on_remove, .driver = { .name = "wm831x-on", }, -- GitLab From 37a432c2278967cc678a4a1c4a1ee751582636e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:05 +0200 Subject: [PATCH 0094/1451] Input: navpoint - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-29-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/navpoint.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/mouse/navpoint.c b/drivers/input/mouse/navpoint.c index 2b7b86eef280e..c00dc1275da23 100644 --- a/drivers/input/mouse/navpoint.c +++ b/drivers/input/mouse/navpoint.c @@ -295,7 +295,7 @@ static int navpoint_probe(struct platform_device *pdev) return error; } -static int navpoint_remove(struct platform_device *pdev) +static void navpoint_remove(struct platform_device *pdev) { const struct navpoint_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -311,8 +311,6 @@ static int navpoint_remove(struct platform_device *pdev) if (gpio_is_valid(pdata->gpio)) gpio_free(pdata->gpio); - - return 0; } static int navpoint_suspend(struct device *dev) @@ -348,7 +346,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(navpoint_pm_ops, static struct platform_driver navpoint_driver = { .probe = navpoint_probe, - .remove = navpoint_remove, + .remove_new = navpoint_remove, .driver = { .name = "navpoint", .pm = pm_sleep_ptr(&navpoint_pm_ops), -- GitLab From fb4f4f37676548778d477f910707f3dffecffe32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:06 +0200 Subject: [PATCH 0095/1451] Input: altera_ps2 - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-30-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/serio/altera_ps2.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/serio/altera_ps2.c b/drivers/input/serio/altera_ps2.c index 9f8d7b332d1b0..c5b634940cfcf 100644 --- a/drivers/input/serio/altera_ps2.c +++ b/drivers/input/serio/altera_ps2.c @@ -125,13 +125,11 @@ static int altera_ps2_probe(struct platform_device *pdev) /* * Remove one device from this driver. */ -static int altera_ps2_remove(struct platform_device *pdev) +static void altera_ps2_remove(struct platform_device *pdev) { struct ps2if *ps2if = platform_get_drvdata(pdev); serio_unregister_port(ps2if->io); - - return 0; } #ifdef CONFIG_OF @@ -148,7 +146,7 @@ MODULE_DEVICE_TABLE(of, altera_ps2_match); */ static struct platform_driver altera_ps2_driver = { .probe = altera_ps2_probe, - .remove = altera_ps2_remove, + .remove_new = altera_ps2_remove, .driver = { .name = DRV_NAME, .of_match_table = of_match_ptr(altera_ps2_match), -- GitLab From d484d0f847e17d4df5d81b8c9ea625d85e929312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:07 +0200 Subject: [PATCH 0096/1451] Input: ams_delta_serio - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-31-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/serio/ams_delta_serio.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c index ec93cb4573c3e..0bd6ae1068099 100644 --- a/drivers/input/serio/ams_delta_serio.c +++ b/drivers/input/serio/ams_delta_serio.c @@ -173,18 +173,16 @@ static int ams_delta_serio_init(struct platform_device *pdev) return 0; } -static int ams_delta_serio_exit(struct platform_device *pdev) +static void ams_delta_serio_exit(struct platform_device *pdev) { struct ams_delta_serio *priv = platform_get_drvdata(pdev); serio_unregister_port(priv->serio); - - return 0; } static struct platform_driver ams_delta_serio_driver = { .probe = ams_delta_serio_init, - .remove = ams_delta_serio_exit, + .remove_new = ams_delta_serio_exit, .driver = { .name = DRIVER_NAME }, -- GitLab From 15514b9c61a4b0e3072d149d09c6c3cbf46f1b7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:08 +0200 Subject: [PATCH 0097/1451] Input: apbps2 - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-32-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/serio/apbps2.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/serio/apbps2.c b/drivers/input/serio/apbps2.c index 3f6866d39b862..dbbb102515209 100644 --- a/drivers/input/serio/apbps2.c +++ b/drivers/input/serio/apbps2.c @@ -187,13 +187,11 @@ static int apbps2_of_probe(struct platform_device *ofdev) return 0; } -static int apbps2_of_remove(struct platform_device *of_dev) +static void apbps2_of_remove(struct platform_device *of_dev) { struct apbps2_priv *priv = platform_get_drvdata(of_dev); serio_unregister_port(priv->io); - - return 0; } static const struct of_device_id apbps2_of_match[] = { @@ -210,7 +208,7 @@ static struct platform_driver apbps2_of_driver = { .of_match_table = apbps2_of_match, }, .probe = apbps2_of_probe, - .remove = apbps2_of_remove, + .remove_new = apbps2_of_remove, }; module_platform_driver(apbps2_of_driver); -- GitLab From da93e8a64f54274bc0a2c9d8238f3b2576f98c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:09 +0200 Subject: [PATCH 0098/1451] Input: arc_ps2 - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-33-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/serio/arc_ps2.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/serio/arc_ps2.c b/drivers/input/serio/arc_ps2.c index a6debb13d5278..9d87268301401 100644 --- a/drivers/input/serio/arc_ps2.c +++ b/drivers/input/serio/arc_ps2.c @@ -232,7 +232,7 @@ static int arc_ps2_probe(struct platform_device *pdev) return 0; } -static int arc_ps2_remove(struct platform_device *pdev) +static void arc_ps2_remove(struct platform_device *pdev) { struct arc_ps2_data *arc_ps2 = platform_get_drvdata(pdev); int i; @@ -244,8 +244,6 @@ static int arc_ps2_remove(struct platform_device *pdev) dev_dbg(&pdev->dev, "frame error count = %i\n", arc_ps2->frame_error); dev_dbg(&pdev->dev, "buffer overflow count = %i\n", arc_ps2->buf_overflow); - - return 0; } #ifdef CONFIG_OF @@ -262,7 +260,7 @@ static struct platform_driver arc_ps2_driver = { .of_match_table = of_match_ptr(arc_ps2_match), }, .probe = arc_ps2_probe, - .remove = arc_ps2_remove, + .remove_new = arc_ps2_remove, }; module_platform_driver(arc_ps2_driver); -- GitLab From 508366de110a042a8ca2cbcc46b6fb637eb6512a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:10 +0200 Subject: [PATCH 0099/1451] Input: ct82c710 - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-34-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/serio/ct82c710.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c index 3da751f4a6bf6..d5c9bb3d01038 100644 --- a/drivers/input/serio/ct82c710.c +++ b/drivers/input/serio/ct82c710.c @@ -180,11 +180,9 @@ static int ct82c710_probe(struct platform_device *dev) return 0; } -static int ct82c710_remove(struct platform_device *dev) +static void ct82c710_remove(struct platform_device *dev) { serio_unregister_port(ct82c710_port); - - return 0; } static struct platform_driver ct82c710_driver = { @@ -192,7 +190,7 @@ static struct platform_driver ct82c710_driver = { .name = "ct82c710", }, .probe = ct82c710_probe, - .remove = ct82c710_remove, + .remove_new = ct82c710_remove, }; -- GitLab From 57f534c1e53d545c19aa711f0eb7f70987ea7655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:11 +0200 Subject: [PATCH 0100/1451] Input: i8042-sparcio - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-35-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042-sparcio.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h index b68793bf05c8c..c2fda54dc384f 100644 --- a/drivers/input/serio/i8042-sparcio.h +++ b/drivers/input/serio/i8042-sparcio.h @@ -82,11 +82,9 @@ static int sparc_i8042_probe(struct platform_device *op) return 0; } -static int sparc_i8042_remove(struct platform_device *op) +static void sparc_i8042_remove(struct platform_device *op) { of_iounmap(kbd_res, kbd_iobase, 8); - - return 0; } static const struct of_device_id sparc_i8042_match[] = { @@ -103,7 +101,7 @@ static struct platform_driver sparc_i8042_driver = { .of_match_table = sparc_i8042_match, }, .probe = sparc_i8042_probe, - .remove = sparc_i8042_remove, + .remove_new = sparc_i8042_remove, }; static bool i8042_is_mr_coffee(void) -- GitLab From 2e760e9b6d4758a5ab86d8fe1030d7f76370f01a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:12 +0200 Subject: [PATCH 0101/1451] Input: i8042 - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-36-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 6dac7c1853a54..9fbb8d31575ae 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -1584,13 +1584,11 @@ static int i8042_probe(struct platform_device *dev) return error; } -static int i8042_remove(struct platform_device *dev) +static void i8042_remove(struct platform_device *dev) { i8042_unregister_ports(); i8042_free_irqs(); i8042_controller_reset(false); - - return 0; } static struct platform_driver i8042_driver = { @@ -1601,7 +1599,7 @@ static struct platform_driver i8042_driver = { #endif }, .probe = i8042_probe, - .remove = i8042_remove, + .remove_new = i8042_remove, .shutdown = i8042_shutdown, }; -- GitLab From 150e792dee9ca8416f3d375e48f2f4d7f701fc6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:13 +0200 Subject: [PATCH 0102/1451] Input: ioc3kbd - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-37-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/serio/ioc3kbd.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/serio/ioc3kbd.c b/drivers/input/serio/ioc3kbd.c index d51bfe912db5b..50552dc7b4f5e 100644 --- a/drivers/input/serio/ioc3kbd.c +++ b/drivers/input/serio/ioc3kbd.c @@ -190,7 +190,7 @@ static int ioc3kbd_probe(struct platform_device *pdev) return 0; } -static int ioc3kbd_remove(struct platform_device *pdev) +static void ioc3kbd_remove(struct platform_device *pdev) { struct ioc3kbd_data *d = platform_get_drvdata(pdev); @@ -198,13 +198,11 @@ static int ioc3kbd_remove(struct platform_device *pdev) serio_unregister_port(d->kbd); serio_unregister_port(d->aux); - - return 0; } static struct platform_driver ioc3kbd_driver = { .probe = ioc3kbd_probe, - .remove = ioc3kbd_remove, + .remove_new = ioc3kbd_remove, .driver = { .name = "ioc3-kbd", }, -- GitLab From b72729b7e6abf3f877856a4030b64c94e388cce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:14 +0200 Subject: [PATCH 0103/1451] Input: maceps2 - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-38-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/serio/maceps2.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c index 629e15089c219..5ccfb82759b35 100644 --- a/drivers/input/serio/maceps2.c +++ b/drivers/input/serio/maceps2.c @@ -148,12 +148,10 @@ static int maceps2_probe(struct platform_device *dev) return 0; } -static int maceps2_remove(struct platform_device *dev) +static void maceps2_remove(struct platform_device *dev) { serio_unregister_port(maceps2_port[0]); serio_unregister_port(maceps2_port[1]); - - return 0; } static struct platform_driver maceps2_driver = { @@ -161,7 +159,7 @@ static struct platform_driver maceps2_driver = { .name = "maceps2", }, .probe = maceps2_probe, - .remove = maceps2_remove, + .remove_new = maceps2_remove, }; static int __init maceps2_init(void) -- GitLab From 9c3c1674ba295243fa03d620b034752e91355b4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:15 +0200 Subject: [PATCH 0104/1451] Input: olpc_apsp - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-39-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/serio/olpc_apsp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/serio/olpc_apsp.c b/drivers/input/serio/olpc_apsp.c index 33a8e5889bd8b..240a714f70818 100644 --- a/drivers/input/serio/olpc_apsp.c +++ b/drivers/input/serio/olpc_apsp.c @@ -238,7 +238,7 @@ static int olpc_apsp_probe(struct platform_device *pdev) return error; } -static int olpc_apsp_remove(struct platform_device *pdev) +static void olpc_apsp_remove(struct platform_device *pdev) { struct olpc_apsp *priv = platform_get_drvdata(pdev); @@ -246,8 +246,6 @@ static int olpc_apsp_remove(struct platform_device *pdev) serio_unregister_port(priv->kbio); serio_unregister_port(priv->padio); - - return 0; } static const struct of_device_id olpc_apsp_dt_ids[] = { @@ -258,7 +256,7 @@ MODULE_DEVICE_TABLE(of, olpc_apsp_dt_ids); static struct platform_driver olpc_apsp_driver = { .probe = olpc_apsp_probe, - .remove = olpc_apsp_remove, + .remove_new = olpc_apsp_remove, .driver = { .name = "olpc-apsp", .of_match_table = olpc_apsp_dt_ids, -- GitLab From 21c3c272a21f99b5915902f8908735cf0a4efe58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:16 +0200 Subject: [PATCH 0105/1451] Input: ps2-gpio - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-40-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/serio/ps2-gpio.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/input/serio/ps2-gpio.c b/drivers/input/serio/ps2-gpio.c index bc1dc484389b4..c3ff60859a035 100644 --- a/drivers/input/serio/ps2-gpio.c +++ b/drivers/input/serio/ps2-gpio.c @@ -476,12 +476,11 @@ static int ps2_gpio_probe(struct platform_device *pdev) return error; } -static int ps2_gpio_remove(struct platform_device *pdev) +static void ps2_gpio_remove(struct platform_device *pdev) { struct ps2_gpio_data *drvdata = platform_get_drvdata(pdev); serio_unregister_port(drvdata->serio); - return 0; } #if defined(CONFIG_OF) @@ -494,7 +493,7 @@ MODULE_DEVICE_TABLE(of, ps2_gpio_match); static struct platform_driver ps2_gpio_driver = { .probe = ps2_gpio_probe, - .remove = ps2_gpio_remove, + .remove_new = ps2_gpio_remove, .driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(ps2_gpio_match), -- GitLab From 68f59e2bb7a7c98bc1b71f1e128b8a09bcaaf27e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:17 +0200 Subject: [PATCH 0106/1451] Input: q40kbd - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-41-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/serio/q40kbd.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index ba04058fc3cbd..3f81f8749cd56 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c @@ -148,7 +148,7 @@ static int q40kbd_probe(struct platform_device *pdev) return error; } -static int q40kbd_remove(struct platform_device *pdev) +static void q40kbd_remove(struct platform_device *pdev) { struct q40kbd *q40kbd = platform_get_drvdata(pdev); @@ -160,15 +160,13 @@ static int q40kbd_remove(struct platform_device *pdev) serio_unregister_port(q40kbd->port); free_irq(Q40_IRQ_KEYBOARD, q40kbd); kfree(q40kbd); - - return 0; } static struct platform_driver q40kbd_driver = { .driver = { .name = "q40kbd", }, - .remove = q40kbd_remove, + .remove_new = q40kbd_remove, }; module_platform_driver_probe(q40kbd_driver, q40kbd_probe); -- GitLab From d4904adb6628597054eaf1144c181759651764f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:18 +0200 Subject: [PATCH 0107/1451] Input: rpckbd - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-42-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/serio/rpckbd.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index e8a9709f32ebb..9bbfefd092c08 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c @@ -133,20 +133,18 @@ static int rpckbd_probe(struct platform_device *dev) return 0; } -static int rpckbd_remove(struct platform_device *dev) +static void rpckbd_remove(struct platform_device *dev) { struct serio *serio = platform_get_drvdata(dev); struct rpckbd_data *rpckbd = serio->port_data; serio_unregister_port(serio); kfree(rpckbd); - - return 0; } static struct platform_driver rpckbd_driver = { .probe = rpckbd_probe, - .remove = rpckbd_remove, + .remove_new = rpckbd_remove, .driver = { .name = "kart", }, -- GitLab From e453a3e6d4024e46c9bc86ce5c61dda536800293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:19 +0200 Subject: [PATCH 0108/1451] Input: sun4i-ps2 - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Jernej Skrabec Link: https://lore.kernel.org/r/20230920125829.1478827-43-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/serio/sun4i-ps2.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c index eb262640192e9..aec66d9f51761 100644 --- a/drivers/input/serio/sun4i-ps2.c +++ b/drivers/input/serio/sun4i-ps2.c @@ -297,7 +297,7 @@ static int sun4i_ps2_probe(struct platform_device *pdev) return error; } -static int sun4i_ps2_remove(struct platform_device *pdev) +static void sun4i_ps2_remove(struct platform_device *pdev) { struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev); @@ -311,8 +311,6 @@ static int sun4i_ps2_remove(struct platform_device *pdev) iounmap(drvdata->reg_base); kfree(drvdata); - - return 0; } static const struct of_device_id sun4i_ps2_match[] = { @@ -324,7 +322,7 @@ MODULE_DEVICE_TABLE(of, sun4i_ps2_match); static struct platform_driver sun4i_ps2_driver = { .probe = sun4i_ps2_probe, - .remove = sun4i_ps2_remove, + .remove_new = sun4i_ps2_remove, .driver = { .name = DRIVER_NAME, .of_match_table = sun4i_ps2_match, -- GitLab From 8df828424d3dce854c5ca10d685c27ab42a4a6f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:20 +0200 Subject: [PATCH 0109/1451] Input: xilinx_ps2 - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-44-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/serio/xilinx_ps2.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index f3d28da70b75c..d8f9faf2b5290 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c @@ -329,7 +329,7 @@ static int xps2_of_probe(struct platform_device *ofdev) * if the driver module is being unloaded. It frees any resources allocated to * the device. */ -static int xps2_of_remove(struct platform_device *of_dev) +static void xps2_of_remove(struct platform_device *of_dev) { struct xps2data *drvdata = platform_get_drvdata(of_dev); struct resource r_mem; /* IO mem resources */ @@ -344,8 +344,6 @@ static int xps2_of_remove(struct platform_device *of_dev) release_mem_region(r_mem.start, resource_size(&r_mem)); kfree(drvdata); - - return 0; } /* Match table for of_platform binding */ @@ -361,7 +359,7 @@ static struct platform_driver xps2_of_driver = { .of_match_table = xps2_of_match, }, .probe = xps2_of_probe, - .remove = xps2_of_remove, + .remove_new = xps2_of_remove, }; module_platform_driver(xps2_of_driver); -- GitLab From b436514915a00031bbc1408b92606ba67c151798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:21 +0200 Subject: [PATCH 0110/1451] Input: da9052_tsi - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-45-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/da9052_tsi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c index f91d0e02ddaee..d71690ce64633 100644 --- a/drivers/input/touchscreen/da9052_tsi.c +++ b/drivers/input/touchscreen/da9052_tsi.c @@ -311,7 +311,7 @@ static int da9052_ts_probe(struct platform_device *pdev) return error; } -static int da9052_ts_remove(struct platform_device *pdev) +static void da9052_ts_remove(struct platform_device *pdev) { struct da9052_tsi *tsi = platform_get_drvdata(pdev); @@ -322,13 +322,11 @@ static int da9052_ts_remove(struct platform_device *pdev) input_unregister_device(tsi->dev); kfree(tsi); - - return 0; } static struct platform_driver da9052_tsi_driver = { .probe = da9052_ts_probe, - .remove = da9052_ts_remove, + .remove_new = da9052_ts_remove, .driver = { .name = "da9052-tsi", }, -- GitLab From 02bb3ecaf9f2e556086e1ab37d1dcb02fc54be8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:22 +0200 Subject: [PATCH 0111/1451] Input: mainstone-wm97xx - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-46-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/mainstone-wm97xx.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c index 85b95ed461e7d..bfbebe245040c 100644 --- a/drivers/input/touchscreen/mainstone-wm97xx.c +++ b/drivers/input/touchscreen/mainstone-wm97xx.c @@ -252,18 +252,16 @@ static int mainstone_wm97xx_probe(struct platform_device *pdev) return wm97xx_register_mach_ops(wm, &mainstone_mach_ops); } -static int mainstone_wm97xx_remove(struct platform_device *pdev) +static void mainstone_wm97xx_remove(struct platform_device *pdev) { struct wm97xx *wm = platform_get_drvdata(pdev); wm97xx_unregister_mach_ops(wm); - - return 0; } static struct platform_driver mainstone_wm97xx_driver = { .probe = mainstone_wm97xx_probe, - .remove = mainstone_wm97xx_remove, + .remove_new = mainstone_wm97xx_remove, .driver = { .name = "wm97xx-touch", }, -- GitLab From 02fd95e114a6f87aed670cb19f2b631b33fc239d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:23 +0200 Subject: [PATCH 0112/1451] Input: mc13783_ts - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-47-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/mc13783_ts.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c index ae0d978c83bfa..cbcd6e34efb7d 100644 --- a/drivers/input/touchscreen/mc13783_ts.c +++ b/drivers/input/touchscreen/mc13783_ts.c @@ -217,18 +217,16 @@ static int __init mc13783_ts_probe(struct platform_device *pdev) return ret; } -static int mc13783_ts_remove(struct platform_device *pdev) +static void mc13783_ts_remove(struct platform_device *pdev) { struct mc13783_ts_priv *priv = platform_get_drvdata(pdev); input_unregister_device(priv->idev); kfree(priv); - - return 0; } static struct platform_driver mc13783_ts_driver = { - .remove = mc13783_ts_remove, + .remove_new = mc13783_ts_remove, .driver = { .name = MC13783_TS_NAME, }, -- GitLab From f6f14e4a33a492d0761ce9f07bd299d7c656bd1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:24 +0200 Subject: [PATCH 0113/1451] Input: pcap_ts - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-48-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/pcap_ts.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/pcap_ts.c b/drivers/input/touchscreen/pcap_ts.c index b2da0194e02ab..821245019feaa 100644 --- a/drivers/input/touchscreen/pcap_ts.c +++ b/drivers/input/touchscreen/pcap_ts.c @@ -197,7 +197,7 @@ static int pcap_ts_probe(struct platform_device *pdev) return err; } -static int pcap_ts_remove(struct platform_device *pdev) +static void pcap_ts_remove(struct platform_device *pdev) { struct pcap_ts *pcap_ts = platform_get_drvdata(pdev); @@ -207,8 +207,6 @@ static int pcap_ts_remove(struct platform_device *pdev) input_unregister_device(pcap_ts->input); kfree(pcap_ts); - - return 0; } #ifdef CONFIG_PM @@ -240,7 +238,7 @@ static const struct dev_pm_ops pcap_ts_pm_ops = { static struct platform_driver pcap_ts_driver = { .probe = pcap_ts_probe, - .remove = pcap_ts_remove, + .remove_new = pcap_ts_remove, .driver = { .name = "pcap-ts", .pm = PCAP_TS_PM_OPS, -- GitLab From 3401b7f542fa5695956f1c9676783d178f2a8b83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:25 +0200 Subject: [PATCH 0114/1451] Input: stmpe-ts - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-49-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/stmpe-ts.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c index 25c45c3a35615..b204fdb2d22c6 100644 --- a/drivers/input/touchscreen/stmpe-ts.c +++ b/drivers/input/touchscreen/stmpe-ts.c @@ -350,13 +350,11 @@ static int stmpe_input_probe(struct platform_device *pdev) return 0; } -static int stmpe_ts_remove(struct platform_device *pdev) +static void stmpe_ts_remove(struct platform_device *pdev) { struct stmpe_touch *ts = platform_get_drvdata(pdev); stmpe_disable(ts->stmpe, STMPE_BLOCK_TOUCHSCREEN); - - return 0; } static struct platform_driver stmpe_ts_driver = { @@ -364,7 +362,7 @@ static struct platform_driver stmpe_ts_driver = { .name = STMPE_TS_NAME, }, .probe = stmpe_input_probe, - .remove = stmpe_ts_remove, + .remove_new = stmpe_ts_remove, }; module_platform_driver(stmpe_ts_driver); -- GitLab From 1b1904f61b3d46d06e8432a5a51ca4b290a693a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:26 +0200 Subject: [PATCH 0115/1451] Input: sun4i-ts - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Jernej Skrabec Link: https://lore.kernel.org/r/20230920125829.1478827-50-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/sun4i-ts.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c index bb3c6072fc827..92b2b840b4b7b 100644 --- a/drivers/input/touchscreen/sun4i-ts.c +++ b/drivers/input/touchscreen/sun4i-ts.c @@ -375,7 +375,7 @@ static int sun4i_ts_probe(struct platform_device *pdev) return 0; } -static int sun4i_ts_remove(struct platform_device *pdev) +static void sun4i_ts_remove(struct platform_device *pdev) { struct sun4i_ts_data *ts = platform_get_drvdata(pdev); @@ -385,8 +385,6 @@ static int sun4i_ts_remove(struct platform_device *pdev) /* Deactivate all IRQs */ writel(0, ts->base + TP_INT_FIFOC); - - return 0; } static const struct of_device_id sun4i_ts_of_match[] = { @@ -403,7 +401,7 @@ static struct platform_driver sun4i_ts_driver = { .of_match_table = sun4i_ts_of_match, }, .probe = sun4i_ts_probe, - .remove = sun4i_ts_remove, + .remove_new = sun4i_ts_remove, }; module_platform_driver(sun4i_ts_driver); -- GitLab From d722a70213f92a1563913d612287e15ed3fad489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:27 +0200 Subject: [PATCH 0116/1451] Input: ti_am335x_tsc - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230920125829.1478827-51-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ti_am335x_tsc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index 9aa4e35fb4f5a..34324f8512ac2 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c @@ -491,7 +491,7 @@ static int titsc_probe(struct platform_device *pdev) return err; } -static int titsc_remove(struct platform_device *pdev) +static void titsc_remove(struct platform_device *pdev) { struct titsc *ts_dev = platform_get_drvdata(pdev); u32 steps; @@ -508,7 +508,6 @@ static int titsc_remove(struct platform_device *pdev) input_unregister_device(ts_dev->input); kfree(ts_dev); - return 0; } static int titsc_suspend(struct device *dev) @@ -552,7 +551,7 @@ MODULE_DEVICE_TABLE(of, ti_tsc_dt_ids); static struct platform_driver ti_tsc_driver = { .probe = titsc_probe, - .remove = titsc_remove, + .remove_new = titsc_remove, .driver = { .name = "TI-am335x-tsc", .pm = pm_sleep_ptr(&titsc_pm_ops), -- GitLab From 33984b4f42b732075cdd19b93ef7608dca23b96f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:28 +0200 Subject: [PATCH 0117/1451] Input: wm831x-ts - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20230920125829.1478827-52-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wm831x-ts.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index 319f57fb9af52..9cee26b63341d 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -374,14 +374,12 @@ static int wm831x_ts_probe(struct platform_device *pdev) return error; } -static int wm831x_ts_remove(struct platform_device *pdev) +static void wm831x_ts_remove(struct platform_device *pdev) { struct wm831x_ts *wm831x_ts = platform_get_drvdata(pdev); free_irq(wm831x_ts->pd_irq, wm831x_ts); free_irq(wm831x_ts->data_irq, wm831x_ts); - - return 0; } static struct platform_driver wm831x_ts_driver = { @@ -389,7 +387,7 @@ static struct platform_driver wm831x_ts_driver = { .name = "wm831x-touch", }, .probe = wm831x_ts_probe, - .remove = wm831x_ts_remove, + .remove_new = wm831x_ts_remove, }; module_platform_driver(wm831x_ts_driver); -- GitLab From c50fdc48643a25f5218f6b8bba4f28e1b4a94708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Sep 2023 14:58:29 +0200 Subject: [PATCH 0118/1451] Input: wm97xx-core - convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20230920125829.1478827-53-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wm97xx-core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index ac3b3dd59488a..f01f6cc9b59fa 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -756,11 +756,9 @@ static int wm97xx_mfd_probe(struct platform_device *pdev) return ret; } -static int wm97xx_mfd_remove(struct platform_device *pdev) +static void wm97xx_mfd_remove(struct platform_device *pdev) { wm97xx_remove(&pdev->dev); - - return 0; } static int wm97xx_suspend(struct device *dev) @@ -878,7 +876,7 @@ static struct platform_driver wm97xx_mfd_driver = { .pm = pm_sleep_ptr(&wm97xx_pm_ops), }, .probe = wm97xx_mfd_probe, - .remove = wm97xx_mfd_remove, + .remove_new = wm97xx_mfd_remove, }; static int __init wm97xx_init(void) -- GitLab From df31b298477e65a01deff0af352be3a61524d930 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:34 -0300 Subject: [PATCH 0119/1451] iommu: Add iommu_ops->identity_domain This allows a driver to set a global static to an IDENTITY domain and the core code will automatically use it whenever an IDENTITY domain is requested. By making it always available it means the IDENTITY can be used in error handling paths to force the iommu driver into a known state. Devices implementing global static identity domains should avoid failing their attach_dev ops. To make global static domains simpler allow drivers to omit their free function and update the iommufd selftest. Convert rockchip to use the new mechanism. Tested-by: Steven Price Tested-by: Marek Szyprowski Tested-by: Nicolin Chen Reviewed-by: Lu Baolu Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/1-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 6 +++++- drivers/iommu/iommufd/selftest.c | 5 ----- drivers/iommu/rockchip-iommu.c | 9 +-------- include/linux/iommu.h | 3 +++ 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 3bfc56df4f781..33bd110709072 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1978,6 +1978,9 @@ static struct iommu_domain *__iommu_domain_alloc(const struct bus_type *bus, if (bus == NULL || bus->iommu_ops == NULL) return NULL; + if (alloc_type == IOMMU_DOMAIN_IDENTITY && bus->iommu_ops->identity_domain) + return bus->iommu_ops->identity_domain; + domain = bus->iommu_ops->domain_alloc(alloc_type); if (!domain) return NULL; @@ -2011,7 +2014,8 @@ void iommu_domain_free(struct iommu_domain *domain) if (domain->type == IOMMU_DOMAIN_SVA) mmdrop(domain->mm); iommu_put_dma_cookie(domain); - domain->ops->free(domain); + if (domain->ops->free) + domain->ops->free(domain); } EXPORT_SYMBOL_GPL(iommu_domain_free); diff --git a/drivers/iommu/iommufd/selftest.c b/drivers/iommu/iommufd/selftest.c index 56506d5753f15..d48a202a7c3b8 100644 --- a/drivers/iommu/iommufd/selftest.c +++ b/drivers/iommu/iommufd/selftest.c @@ -111,10 +111,6 @@ struct selftest_obj { }; }; -static void mock_domain_blocking_free(struct iommu_domain *domain) -{ -} - static int mock_domain_nop_attach(struct iommu_domain *domain, struct device *dev) { @@ -122,7 +118,6 @@ static int mock_domain_nop_attach(struct iommu_domain *domain, } static const struct iommu_domain_ops mock_blocking_ops = { - .free = mock_domain_blocking_free, .attach_dev = mock_domain_nop_attach, }; diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index 8ff69fbf9f65d..033678f2f8b3a 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -989,13 +989,8 @@ static int rk_iommu_identity_attach(struct iommu_domain *identity_domain, return 0; } -static void rk_iommu_identity_free(struct iommu_domain *domain) -{ -} - static struct iommu_domain_ops rk_identity_ops = { .attach_dev = rk_iommu_identity_attach, - .free = rk_iommu_identity_free, }; static struct iommu_domain rk_identity_domain = { @@ -1059,9 +1054,6 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type) { struct rk_iommu_domain *rk_domain; - if (type == IOMMU_DOMAIN_IDENTITY) - return &rk_identity_domain; - if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA) return NULL; @@ -1186,6 +1178,7 @@ static int rk_iommu_of_xlate(struct device *dev, } static const struct iommu_ops rk_iommu_ops = { + .identity_domain = &rk_identity_domain, .domain_alloc = rk_iommu_domain_alloc, .probe_device = rk_iommu_probe_device, .release_device = rk_iommu_release_device, diff --git a/include/linux/iommu.h b/include/linux/iommu.h index c50a769d569a6..d0920b2a9f1c0 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -260,6 +260,8 @@ struct iommu_iotlb_gather { * will be blocked by the hardware. * @pgsize_bitmap: bitmap of all possible supported page sizes * @owner: Driver module providing these ops + * @identity_domain: An always available, always attachable identity + * translation. */ struct iommu_ops { bool (*capable)(struct device *dev, enum iommu_cap); @@ -294,6 +296,7 @@ struct iommu_ops { const struct iommu_domain_ops *default_domain_ops; unsigned long pgsize_bitmap; struct module *owner; + struct iommu_domain *identity_domain; }; /** -- GitLab From 1c68cbc64fe6ac01dc242ba562344303031a76fb Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:35 -0300 Subject: [PATCH 0120/1451] iommu: Add IOMMU_DOMAIN_PLATFORM This is used when the iommu driver is taking control of the dma_ops, currently only on S390 and power spapr. It is designed to preserve the original ops->detach_dev() semantic that these S390 was built around. Provide an opaque domain type and a 'default_domain' ops value that allows the driver to trivially force any single domain as the default domain. Update iommufd selftest to use this instead of set_platform_dma_ops Reviewed-by: Lu Baolu Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/2-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 13 +++++++++++++ drivers/iommu/iommufd/selftest.c | 14 +++++--------- include/linux/iommu.h | 8 ++++++++ 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 33bd110709072..0e13e566581c2 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -184,6 +184,8 @@ static const char *iommu_domain_type_str(unsigned int t) case IOMMU_DOMAIN_DMA: case IOMMU_DOMAIN_DMA_FQ: return "Translated"; + case IOMMU_DOMAIN_PLATFORM: + return "Platform"; default: return "Unknown"; } @@ -1752,6 +1754,17 @@ iommu_group_alloc_default_domain(struct iommu_group *group, int req_type) lockdep_assert_held(&group->mutex); + /* + * Allow legacy drivers to specify the domain that will be the default + * domain. This should always be either an IDENTITY/BLOCKED/PLATFORM + * domain. Do not use in new drivers. + */ + if (bus->iommu_ops->default_domain) { + if (req_type) + return ERR_PTR(-EINVAL); + return bus->iommu_ops->default_domain; + } + if (req_type) return __iommu_group_alloc_default_domain(bus, group, req_type); diff --git a/drivers/iommu/iommufd/selftest.c b/drivers/iommu/iommufd/selftest.c index d48a202a7c3b8..fb981ba97c4e8 100644 --- a/drivers/iommu/iommufd/selftest.c +++ b/drivers/iommu/iommufd/selftest.c @@ -281,14 +281,6 @@ static bool mock_domain_capable(struct device *dev, enum iommu_cap cap) return cap == IOMMU_CAP_CACHE_COHERENCY; } -static void mock_domain_set_plaform_dma_ops(struct device *dev) -{ - /* - * mock doesn't setup default domains because we can't hook into the - * normal probe path - */ -} - static struct iommu_device mock_iommu_device = { }; @@ -298,12 +290,16 @@ static struct iommu_device *mock_probe_device(struct device *dev) } static const struct iommu_ops mock_ops = { + /* + * IOMMU_DOMAIN_BLOCKED cannot be returned from def_domain_type() + * because it is zero. + */ + .default_domain = &mock_blocking_domain, .owner = THIS_MODULE, .pgsize_bitmap = MOCK_IO_PAGE_SIZE, .hw_info = mock_domain_hw_info, .domain_alloc = mock_domain_alloc, .capable = mock_domain_capable, - .set_platform_dma_ops = mock_domain_set_plaform_dma_ops, .device_group = generic_device_group, .probe_device = mock_probe_device, .default_domain_ops = diff --git a/include/linux/iommu.h b/include/linux/iommu.h index d0920b2a9f1c0..a05480be05fd0 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -64,6 +64,7 @@ struct iommu_domain_geometry { #define __IOMMU_DOMAIN_DMA_FQ (1U << 3) /* DMA-API uses flush queue */ #define __IOMMU_DOMAIN_SVA (1U << 4) /* Shared process address space */ +#define __IOMMU_DOMAIN_PLATFORM (1U << 5) #define IOMMU_DOMAIN_ALLOC_FLAGS ~__IOMMU_DOMAIN_DMA_FQ /* @@ -81,6 +82,8 @@ struct iommu_domain_geometry { * invalidation. * IOMMU_DOMAIN_SVA - DMA addresses are shared process addresses * represented by mm_struct's. + * IOMMU_DOMAIN_PLATFORM - Legacy domain for drivers that do their own + * dma_api stuff. Do not use in new drivers. */ #define IOMMU_DOMAIN_BLOCKED (0U) #define IOMMU_DOMAIN_IDENTITY (__IOMMU_DOMAIN_PT) @@ -91,6 +94,7 @@ struct iommu_domain_geometry { __IOMMU_DOMAIN_DMA_API | \ __IOMMU_DOMAIN_DMA_FQ) #define IOMMU_DOMAIN_SVA (__IOMMU_DOMAIN_SVA) +#define IOMMU_DOMAIN_PLATFORM (__IOMMU_DOMAIN_PLATFORM) struct iommu_domain { unsigned type; @@ -262,6 +266,9 @@ struct iommu_iotlb_gather { * @owner: Driver module providing these ops * @identity_domain: An always available, always attachable identity * translation. + * @default_domain: If not NULL this will always be set as the default domain. + * This should be an IDENTITY/BLOCKED/PLATFORM domain. + * Do not use in new drivers. */ struct iommu_ops { bool (*capable)(struct device *dev, enum iommu_cap); @@ -297,6 +304,7 @@ struct iommu_ops { unsigned long pgsize_bitmap; struct module *owner; struct iommu_domain *identity_domain; + struct iommu_domain *default_domain; }; /** -- GitLab From 2ad56efa80dba89162106c06ebc00b611325e584 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:36 -0300 Subject: [PATCH 0121/1451] powerpc/iommu: Setup a default domain and remove set_platform_dma_ops POWER is using the set_platform_dma_ops() callback to hook up its private dma_ops, but this is buired under some indirection and is weirdly happening for a BLOCKED domain as well. For better documentation create a PLATFORM domain to manage the dma_ops, since that is what it is for, and make the BLOCKED domain an alias for it. BLOCKED is required for VFIO. Also removes the leaky allocation of the BLOCKED domain by using a global static. Reviewed-by: Lu Baolu Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/3-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- arch/powerpc/kernel/iommu.c | 38 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index 14251bc5219eb..d6ad3fde85a21 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -1280,7 +1280,7 @@ struct iommu_table_group_ops spapr_tce_table_group_ops = { /* * A simple iommu_ops to allow less cruft in generic VFIO code. */ -static int spapr_tce_blocking_iommu_attach_dev(struct iommu_domain *dom, +static int spapr_tce_platform_iommu_attach_dev(struct iommu_domain *dom, struct device *dev) { struct iommu_group *grp = iommu_group_get(dev); @@ -1297,17 +1297,22 @@ static int spapr_tce_blocking_iommu_attach_dev(struct iommu_domain *dom, return ret; } -static void spapr_tce_blocking_iommu_set_platform_dma(struct device *dev) -{ - struct iommu_group *grp = iommu_group_get(dev); - struct iommu_table_group *table_group; +static const struct iommu_domain_ops spapr_tce_platform_domain_ops = { + .attach_dev = spapr_tce_platform_iommu_attach_dev, +}; - table_group = iommu_group_get_iommudata(grp); - table_group->ops->release_ownership(table_group); -} +static struct iommu_domain spapr_tce_platform_domain = { + .type = IOMMU_DOMAIN_PLATFORM, + .ops = &spapr_tce_platform_domain_ops, +}; -static const struct iommu_domain_ops spapr_tce_blocking_domain_ops = { - .attach_dev = spapr_tce_blocking_iommu_attach_dev, +static struct iommu_domain spapr_tce_blocked_domain = { + .type = IOMMU_DOMAIN_BLOCKED, + /* + * FIXME: SPAPR mixes blocked and platform behaviors, the blocked domain + * also sets the dma_api ops + */ + .ops = &spapr_tce_platform_domain_ops, }; static bool spapr_tce_iommu_capable(struct device *dev, enum iommu_cap cap) @@ -1324,18 +1329,9 @@ static bool spapr_tce_iommu_capable(struct device *dev, enum iommu_cap cap) static struct iommu_domain *spapr_tce_iommu_domain_alloc(unsigned int type) { - struct iommu_domain *dom; - if (type != IOMMU_DOMAIN_BLOCKED) return NULL; - - dom = kzalloc(sizeof(*dom), GFP_KERNEL); - if (!dom) - return NULL; - - dom->ops = &spapr_tce_blocking_domain_ops; - - return dom; + return &spapr_tce_blocked_domain; } static struct iommu_device *spapr_tce_iommu_probe_device(struct device *dev) @@ -1371,12 +1367,12 @@ static struct iommu_group *spapr_tce_iommu_device_group(struct device *dev) } static const struct iommu_ops spapr_tce_iommu_ops = { + .default_domain = &spapr_tce_platform_domain, .capable = spapr_tce_iommu_capable, .domain_alloc = spapr_tce_iommu_domain_alloc, .probe_device = spapr_tce_iommu_probe_device, .release_device = spapr_tce_iommu_release_device, .device_group = spapr_tce_iommu_device_group, - .set_platform_dma_ops = spapr_tce_blocking_iommu_set_platform_dma, }; static struct attribute *spapr_tce_iommu_attrs[] = { -- GitLab From e04c7487a6655722172e93e8f36e51d6ab279f86 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:37 -0300 Subject: [PATCH 0122/1451] iommu: Add IOMMU_DOMAIN_PLATFORM for S390 The PLATFORM domain will be set as the default domain and attached as normal during probe. The driver will ignore the initial attach from a NULL domain to the PLATFORM domain. After this, the PLATFORM domain's attach_dev will be called whenever we detach from an UNMANAGED domain (eg for VFIO). This is the same time the original design would have called op->detach_dev(). This is temporary until the S390 dma-iommu.c conversion is merged. Tested-by: Heiko Stuebner Tested-by: Niklas Schnelle Reviewed-by: Lu Baolu Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/4-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/s390-iommu.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c index fbf59a8db29b1..f0c867c57a5b9 100644 --- a/drivers/iommu/s390-iommu.c +++ b/drivers/iommu/s390-iommu.c @@ -142,14 +142,31 @@ static int s390_iommu_attach_device(struct iommu_domain *domain, return 0; } -static void s390_iommu_set_platform_dma(struct device *dev) +/* + * Switch control over the IOMMU to S390's internal dma_api ops + */ +static int s390_iommu_platform_attach(struct iommu_domain *platform_domain, + struct device *dev) { struct zpci_dev *zdev = to_zpci_dev(dev); + if (!zdev->s390_domain) + return 0; + __s390_iommu_detach_device(zdev); zpci_dma_init_device(zdev); + return 0; } +static struct iommu_domain_ops s390_iommu_platform_ops = { + .attach_dev = s390_iommu_platform_attach, +}; + +static struct iommu_domain s390_iommu_platform_domain = { + .type = IOMMU_DOMAIN_PLATFORM, + .ops = &s390_iommu_platform_ops, +}; + static void s390_iommu_get_resv_regions(struct device *dev, struct list_head *list) { @@ -428,12 +445,12 @@ void zpci_destroy_iommu(struct zpci_dev *zdev) } static const struct iommu_ops s390_iommu_ops = { + .default_domain = &s390_iommu_platform_domain, .capable = s390_iommu_capable, .domain_alloc = s390_domain_alloc, .probe_device = s390_iommu_probe_device, .release_device = s390_iommu_release_device, .device_group = generic_device_group, - .set_platform_dma_ops = s390_iommu_set_platform_dma, .pgsize_bitmap = SZ_4K, .get_resv_regions = s390_iommu_get_resv_regions, .default_domain_ops = &(const struct iommu_domain_ops) { -- GitLab From 8565915e75581ba540527d1d9a2b89620002a0d0 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:38 -0300 Subject: [PATCH 0123/1451] iommu/fsl_pamu: Implement a PLATFORM domain This driver is nonsensical. To not block migrating the core API away from NULL default_domains give it a hacky of a PLATFORM domain that keeps it working exactly as it always did. Leave some comments around to warn away any future people looking at this. Reviewed-by: Lu Baolu Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/5-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/fsl_pamu_domain.c | 41 ++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c index 4ac0e247ec2b5..e9d2bff4659b7 100644 --- a/drivers/iommu/fsl_pamu_domain.c +++ b/drivers/iommu/fsl_pamu_domain.c @@ -196,6 +196,13 @@ static struct iommu_domain *fsl_pamu_domain_alloc(unsigned type) { struct fsl_dma_domain *dma_domain; + /* + * FIXME: This isn't creating an unmanaged domain since the + * default_domain_ops do not have any map/unmap function it doesn't meet + * the requirements for __IOMMU_DOMAIN_PAGING. The only purpose seems to + * allow drivers/soc/fsl/qbman/qman_portal.c to do + * fsl_pamu_configure_l1_stash() + */ if (type != IOMMU_DOMAIN_UNMANAGED) return NULL; @@ -283,15 +290,33 @@ static int fsl_pamu_attach_device(struct iommu_domain *domain, return ret; } -static void fsl_pamu_set_platform_dma(struct device *dev) +/* + * FIXME: fsl/pamu is completely broken in terms of how it works with the iommu + * API. Immediately after probe the HW is left in an IDENTITY translation and + * the driver provides a non-working UNMANAGED domain that it can switch over + * to. However it cannot switch back to an IDENTITY translation, instead it + * switches to what looks like BLOCKING. + */ +static int fsl_pamu_platform_attach(struct iommu_domain *platform_domain, + struct device *dev) { struct iommu_domain *domain = iommu_get_domain_for_dev(dev); - struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain); + struct fsl_dma_domain *dma_domain; const u32 *prop; int len; struct pci_dev *pdev = NULL; struct pci_controller *pci_ctl; + /* + * Hack to keep things working as they always have, only leaving an + * UNMANAGED domain makes it BLOCKING. + */ + if (domain == platform_domain || !domain || + domain->type != IOMMU_DOMAIN_UNMANAGED) + return 0; + + dma_domain = to_fsl_dma_domain(domain); + /* * Use LIODN of the PCI controller while detaching a * PCI device. @@ -312,8 +337,18 @@ static void fsl_pamu_set_platform_dma(struct device *dev) detach_device(dev, dma_domain); else pr_debug("missing fsl,liodn property at %pOF\n", dev->of_node); + return 0; } +static struct iommu_domain_ops fsl_pamu_platform_ops = { + .attach_dev = fsl_pamu_platform_attach, +}; + +static struct iommu_domain fsl_pamu_platform_domain = { + .type = IOMMU_DOMAIN_PLATFORM, + .ops = &fsl_pamu_platform_ops, +}; + /* Set the domain stash attribute */ int fsl_pamu_configure_l1_stash(struct iommu_domain *domain, u32 cpu) { @@ -395,11 +430,11 @@ static struct iommu_device *fsl_pamu_probe_device(struct device *dev) } static const struct iommu_ops fsl_pamu_ops = { + .default_domain = &fsl_pamu_platform_domain, .capable = fsl_pamu_capable, .domain_alloc = fsl_pamu_domain_alloc, .probe_device = fsl_pamu_probe_device, .device_group = fsl_pamu_device_group, - .set_platform_dma_ops = fsl_pamu_set_platform_dma, .default_domain_ops = &(const struct iommu_domain_ops) { .attach_dev = fsl_pamu_attach_device, .iova_to_phys = fsl_pamu_iova_to_phys, -- GitLab From c462944901319cb52ec0d0382dcea64f4f6f70e8 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:39 -0300 Subject: [PATCH 0124/1451] iommu/tegra-gart: Remove tegra-gart Thierry says this is not used anymore, and doesn't think it makes sense as an iommu driver. The HW it supports is about 10 years old now and newer HW uses different IOMMU drivers. As this is the only driver with a GART approach, and it doesn't really meet the driver expectations from the IOMMU core, let's just remove it so we don't have to think about how to make it fit in. It has a number of identified problems: - The assignment of iommu_groups doesn't match the HW behavior - It claims to have an UNMANAGED domain but it is really an IDENTITY domain with a translation aperture. This is inconsistent with the core expectation for security sensitive operations - It doesn't implement a SW page table under struct iommu_domain so * It can't accept a map until the domain is attached * It forgets about all maps after the domain is detached * It doesn't clear the HW of maps once the domain is detached (made worse by having the wrong groups) Cc: Thierry Reding Cc: Dmitry Osipenko Acked-by: Thierry Reding Reviewed-by: Lu Baolu Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/6-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- arch/arm/configs/multi_v7_defconfig | 1 - arch/arm/configs/tegra_defconfig | 1 - drivers/iommu/Kconfig | 11 - drivers/iommu/Makefile | 1 - drivers/iommu/tegra-gart.c | 371 ---------------------------- drivers/memory/tegra/mc.c | 34 --- drivers/memory/tegra/tegra20.c | 28 --- include/soc/tegra/mc.h | 26 -- 8 files changed, 473 deletions(-) delete mode 100644 drivers/iommu/tegra-gart.c diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 23fc49f23d255..5dc4416b75d36 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -1073,7 +1073,6 @@ CONFIG_QCOM_IPCC=y CONFIG_OMAP_IOMMU=y CONFIG_OMAP_IOMMU_DEBUG=y CONFIG_ROCKCHIP_IOMMU=y -CONFIG_TEGRA_IOMMU_GART=y CONFIG_TEGRA_IOMMU_SMMU=y CONFIG_EXYNOS_IOMMU=y CONFIG_QCOM_IOMMU=y diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig index 613f07b8ce150..8635b7216bfc5 100644 --- a/arch/arm/configs/tegra_defconfig +++ b/arch/arm/configs/tegra_defconfig @@ -292,7 +292,6 @@ CONFIG_CHROME_PLATFORMS=y CONFIG_CROS_EC=y CONFIG_CROS_EC_I2C=m CONFIG_CROS_EC_SPI=m -CONFIG_TEGRA_IOMMU_GART=y CONFIG_TEGRA_IOMMU_SMMU=y CONFIG_ARCH_TEGRA_2x_SOC=y CONFIG_ARCH_TEGRA_3x_SOC=y diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 2b12b583ef4b1..cd6727898b117 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -236,17 +236,6 @@ config SUN50I_IOMMU help Support for the IOMMU introduced in the Allwinner H6 SoCs. -config TEGRA_IOMMU_GART - bool "Tegra GART IOMMU Support" - depends on ARCH_TEGRA_2x_SOC - depends on TEGRA_MC - select IOMMU_API - help - Enables support for remapping discontiguous physical memory - shared with the operating system into contiguous I/O virtual - space through the GART (Graphics Address Relocation Table) - hardware included on Tegra SoCs. - config TEGRA_IOMMU_SMMU bool "NVIDIA Tegra SMMU Support" depends on ARCH_TEGRA diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index 769e43d780ce8..95ad9dbfbda02 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile @@ -20,7 +20,6 @@ obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o obj-$(CONFIG_ROCKCHIP_IOMMU) += rockchip-iommu.o obj-$(CONFIG_SUN50I_IOMMU) += sun50i-iommu.o -obj-$(CONFIG_TEGRA_IOMMU_GART) += tegra-gart.o obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o obj-$(CONFIG_EXYNOS_IOMMU) += exynos-iommu.o obj-$(CONFIG_FSL_PAMU) += fsl_pamu.o fsl_pamu_domain.o diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c deleted file mode 100644 index a482ff838b533..0000000000000 --- a/drivers/iommu/tegra-gart.c +++ /dev/null @@ -1,371 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * IOMMU API for Graphics Address Relocation Table on Tegra20 - * - * Copyright (c) 2010-2012, NVIDIA CORPORATION. All rights reserved. - * - * Author: Hiroshi DOYU - */ - -#define dev_fmt(fmt) "gart: " fmt - -#include -#include -#include -#include -#include -#include -#include - -#include - -#define GART_REG_BASE 0x24 -#define GART_CONFIG (0x24 - GART_REG_BASE) -#define GART_ENTRY_ADDR (0x28 - GART_REG_BASE) -#define GART_ENTRY_DATA (0x2c - GART_REG_BASE) - -#define GART_ENTRY_PHYS_ADDR_VALID BIT(31) - -#define GART_PAGE_SHIFT 12 -#define GART_PAGE_SIZE (1 << GART_PAGE_SHIFT) -#define GART_PAGE_MASK GENMASK(30, GART_PAGE_SHIFT) - -/* bitmap of the page sizes currently supported */ -#define GART_IOMMU_PGSIZES (GART_PAGE_SIZE) - -struct gart_device { - void __iomem *regs; - u32 *savedata; - unsigned long iovmm_base; /* offset to vmm_area start */ - unsigned long iovmm_end; /* offset to vmm_area end */ - spinlock_t pte_lock; /* for pagetable */ - spinlock_t dom_lock; /* for active domain */ - unsigned int active_devices; /* number of active devices */ - struct iommu_domain *active_domain; /* current active domain */ - struct iommu_device iommu; /* IOMMU Core handle */ - struct device *dev; -}; - -static struct gart_device *gart_handle; /* unique for a system */ - -static bool gart_debug; - -/* - * Any interaction between any block on PPSB and a block on APB or AHB - * must have these read-back to ensure the APB/AHB bus transaction is - * complete before initiating activity on the PPSB block. - */ -#define FLUSH_GART_REGS(gart) readl_relaxed((gart)->regs + GART_CONFIG) - -#define for_each_gart_pte(gart, iova) \ - for (iova = gart->iovmm_base; \ - iova < gart->iovmm_end; \ - iova += GART_PAGE_SIZE) - -static inline void gart_set_pte(struct gart_device *gart, - unsigned long iova, unsigned long pte) -{ - writel_relaxed(iova, gart->regs + GART_ENTRY_ADDR); - writel_relaxed(pte, gart->regs + GART_ENTRY_DATA); -} - -static inline unsigned long gart_read_pte(struct gart_device *gart, - unsigned long iova) -{ - unsigned long pte; - - writel_relaxed(iova, gart->regs + GART_ENTRY_ADDR); - pte = readl_relaxed(gart->regs + GART_ENTRY_DATA); - - return pte; -} - -static void do_gart_setup(struct gart_device *gart, const u32 *data) -{ - unsigned long iova; - - for_each_gart_pte(gart, iova) - gart_set_pte(gart, iova, data ? *(data++) : 0); - - writel_relaxed(1, gart->regs + GART_CONFIG); - FLUSH_GART_REGS(gart); -} - -static inline bool gart_iova_range_invalid(struct gart_device *gart, - unsigned long iova, size_t bytes) -{ - return unlikely(iova < gart->iovmm_base || bytes != GART_PAGE_SIZE || - iova + bytes > gart->iovmm_end); -} - -static inline bool gart_pte_valid(struct gart_device *gart, unsigned long iova) -{ - return !!(gart_read_pte(gart, iova) & GART_ENTRY_PHYS_ADDR_VALID); -} - -static int gart_iommu_attach_dev(struct iommu_domain *domain, - struct device *dev) -{ - struct gart_device *gart = gart_handle; - int ret = 0; - - spin_lock(&gart->dom_lock); - - if (gart->active_domain && gart->active_domain != domain) { - ret = -EINVAL; - } else if (dev_iommu_priv_get(dev) != domain) { - dev_iommu_priv_set(dev, domain); - gart->active_domain = domain; - gart->active_devices++; - } - - spin_unlock(&gart->dom_lock); - - return ret; -} - -static void gart_iommu_set_platform_dma(struct device *dev) -{ - struct iommu_domain *domain = iommu_get_domain_for_dev(dev); - struct gart_device *gart = gart_handle; - - spin_lock(&gart->dom_lock); - - if (dev_iommu_priv_get(dev) == domain) { - dev_iommu_priv_set(dev, NULL); - - if (--gart->active_devices == 0) - gart->active_domain = NULL; - } - - spin_unlock(&gart->dom_lock); -} - -static struct iommu_domain *gart_iommu_domain_alloc(unsigned type) -{ - struct iommu_domain *domain; - - if (type != IOMMU_DOMAIN_UNMANAGED) - return NULL; - - domain = kzalloc(sizeof(*domain), GFP_KERNEL); - if (domain) { - domain->geometry.aperture_start = gart_handle->iovmm_base; - domain->geometry.aperture_end = gart_handle->iovmm_end - 1; - domain->geometry.force_aperture = true; - } - - return domain; -} - -static void gart_iommu_domain_free(struct iommu_domain *domain) -{ - WARN_ON(gart_handle->active_domain == domain); - kfree(domain); -} - -static inline int __gart_iommu_map(struct gart_device *gart, unsigned long iova, - unsigned long pa) -{ - if (unlikely(gart_debug && gart_pte_valid(gart, iova))) { - dev_err(gart->dev, "Page entry is in-use\n"); - return -EINVAL; - } - - gart_set_pte(gart, iova, GART_ENTRY_PHYS_ADDR_VALID | pa); - - return 0; -} - -static int gart_iommu_map(struct iommu_domain *domain, unsigned long iova, - phys_addr_t pa, size_t bytes, int prot, gfp_t gfp) -{ - struct gart_device *gart = gart_handle; - int ret; - - if (gart_iova_range_invalid(gart, iova, bytes)) - return -EINVAL; - - spin_lock(&gart->pte_lock); - ret = __gart_iommu_map(gart, iova, (unsigned long)pa); - spin_unlock(&gart->pte_lock); - - return ret; -} - -static inline int __gart_iommu_unmap(struct gart_device *gart, - unsigned long iova) -{ - if (unlikely(gart_debug && !gart_pte_valid(gart, iova))) { - dev_err(gart->dev, "Page entry is invalid\n"); - return -EINVAL; - } - - gart_set_pte(gart, iova, 0); - - return 0; -} - -static size_t gart_iommu_unmap(struct iommu_domain *domain, unsigned long iova, - size_t bytes, struct iommu_iotlb_gather *gather) -{ - struct gart_device *gart = gart_handle; - int err; - - if (gart_iova_range_invalid(gart, iova, bytes)) - return 0; - - spin_lock(&gart->pte_lock); - err = __gart_iommu_unmap(gart, iova); - spin_unlock(&gart->pte_lock); - - return err ? 0 : bytes; -} - -static phys_addr_t gart_iommu_iova_to_phys(struct iommu_domain *domain, - dma_addr_t iova) -{ - struct gart_device *gart = gart_handle; - unsigned long pte; - - if (gart_iova_range_invalid(gart, iova, GART_PAGE_SIZE)) - return -EINVAL; - - spin_lock(&gart->pte_lock); - pte = gart_read_pte(gart, iova); - spin_unlock(&gart->pte_lock); - - return pte & GART_PAGE_MASK; -} - -static struct iommu_device *gart_iommu_probe_device(struct device *dev) -{ - if (!dev_iommu_fwspec_get(dev)) - return ERR_PTR(-ENODEV); - - return &gart_handle->iommu; -} - -static int gart_iommu_of_xlate(struct device *dev, - struct of_phandle_args *args) -{ - return 0; -} - -static void gart_iommu_sync_map(struct iommu_domain *domain, unsigned long iova, - size_t size) -{ - FLUSH_GART_REGS(gart_handle); -} - -static void gart_iommu_sync(struct iommu_domain *domain, - struct iommu_iotlb_gather *gather) -{ - size_t length = gather->end - gather->start + 1; - - gart_iommu_sync_map(domain, gather->start, length); -} - -static const struct iommu_ops gart_iommu_ops = { - .domain_alloc = gart_iommu_domain_alloc, - .probe_device = gart_iommu_probe_device, - .device_group = generic_device_group, - .set_platform_dma_ops = gart_iommu_set_platform_dma, - .pgsize_bitmap = GART_IOMMU_PGSIZES, - .of_xlate = gart_iommu_of_xlate, - .default_domain_ops = &(const struct iommu_domain_ops) { - .attach_dev = gart_iommu_attach_dev, - .map = gart_iommu_map, - .unmap = gart_iommu_unmap, - .iova_to_phys = gart_iommu_iova_to_phys, - .iotlb_sync_map = gart_iommu_sync_map, - .iotlb_sync = gart_iommu_sync, - .free = gart_iommu_domain_free, - } -}; - -int tegra_gart_suspend(struct gart_device *gart) -{ - u32 *data = gart->savedata; - unsigned long iova; - - /* - * All GART users shall be suspended at this point. Disable - * address translation to trap all GART accesses as invalid - * memory accesses. - */ - writel_relaxed(0, gart->regs + GART_CONFIG); - FLUSH_GART_REGS(gart); - - for_each_gart_pte(gart, iova) - *(data++) = gart_read_pte(gart, iova); - - return 0; -} - -int tegra_gart_resume(struct gart_device *gart) -{ - do_gart_setup(gart, gart->savedata); - - return 0; -} - -struct gart_device *tegra_gart_probe(struct device *dev, struct tegra_mc *mc) -{ - struct gart_device *gart; - struct resource *res; - int err; - - BUILD_BUG_ON(PAGE_SHIFT != GART_PAGE_SHIFT); - - /* the GART memory aperture is required */ - res = platform_get_resource(to_platform_device(dev), IORESOURCE_MEM, 1); - if (!res) { - dev_err(dev, "Memory aperture resource unavailable\n"); - return ERR_PTR(-ENXIO); - } - - gart = kzalloc(sizeof(*gart), GFP_KERNEL); - if (!gart) - return ERR_PTR(-ENOMEM); - - gart_handle = gart; - - gart->dev = dev; - gart->regs = mc->regs + GART_REG_BASE; - gart->iovmm_base = res->start; - gart->iovmm_end = res->end + 1; - spin_lock_init(&gart->pte_lock); - spin_lock_init(&gart->dom_lock); - - do_gart_setup(gart, NULL); - - err = iommu_device_sysfs_add(&gart->iommu, dev, NULL, "gart"); - if (err) - goto free_gart; - - err = iommu_device_register(&gart->iommu, &gart_iommu_ops, dev); - if (err) - goto remove_sysfs; - - gart->savedata = vmalloc(resource_size(res) / GART_PAGE_SIZE * - sizeof(u32)); - if (!gart->savedata) { - err = -ENOMEM; - goto unregister_iommu; - } - - return gart; - -unregister_iommu: - iommu_device_unregister(&gart->iommu); -remove_sysfs: - iommu_device_sysfs_remove(&gart->iommu); -free_gart: - kfree(gart); - - return ERR_PTR(err); -} - -module_param(gart_debug, bool, 0644); -MODULE_PARM_DESC(gart_debug, "Enable GART debugging"); diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index 67d6e70b4eab1..a083921a8968b 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -979,35 +979,6 @@ static int tegra_mc_probe(struct platform_device *pdev) } } - if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && !mc->soc->smmu) { - mc->gart = tegra_gart_probe(&pdev->dev, mc); - if (IS_ERR(mc->gart)) { - dev_err(&pdev->dev, "failed to probe GART: %ld\n", - PTR_ERR(mc->gart)); - mc->gart = NULL; - } - } - - return 0; -} - -static int __maybe_unused tegra_mc_suspend(struct device *dev) -{ - struct tegra_mc *mc = dev_get_drvdata(dev); - - if (mc->soc->ops && mc->soc->ops->suspend) - return mc->soc->ops->suspend(mc); - - return 0; -} - -static int __maybe_unused tegra_mc_resume(struct device *dev) -{ - struct tegra_mc *mc = dev_get_drvdata(dev); - - if (mc->soc->ops && mc->soc->ops->resume) - return mc->soc->ops->resume(mc); - return 0; } @@ -1020,15 +991,10 @@ static void tegra_mc_sync_state(struct device *dev) icc_sync_state(dev); } -static const struct dev_pm_ops tegra_mc_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(tegra_mc_suspend, tegra_mc_resume) -}; - static struct platform_driver tegra_mc_driver = { .driver = { .name = "tegra-mc", .of_match_table = tegra_mc_of_match, - .pm = &tegra_mc_pm_ops, .suppress_bind_attrs = true, .sync_state = tegra_mc_sync_state, }, diff --git a/drivers/memory/tegra/tegra20.c b/drivers/memory/tegra/tegra20.c index 544bfd216a220..aa4b97d5e7323 100644 --- a/drivers/memory/tegra/tegra20.c +++ b/drivers/memory/tegra/tegra20.c @@ -688,32 +688,6 @@ static int tegra20_mc_probe(struct tegra_mc *mc) return 0; } -static int tegra20_mc_suspend(struct tegra_mc *mc) -{ - int err; - - if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && mc->gart) { - err = tegra_gart_suspend(mc->gart); - if (err < 0) - return err; - } - - return 0; -} - -static int tegra20_mc_resume(struct tegra_mc *mc) -{ - int err; - - if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && mc->gart) { - err = tegra_gart_resume(mc->gart); - if (err < 0) - return err; - } - - return 0; -} - static irqreturn_t tegra20_mc_handle_irq(int irq, void *data) { struct tegra_mc *mc = data; @@ -789,8 +763,6 @@ static irqreturn_t tegra20_mc_handle_irq(int irq, void *data) static const struct tegra_mc_ops tegra20_mc_ops = { .probe = tegra20_mc_probe, - .suspend = tegra20_mc_suspend, - .resume = tegra20_mc_resume, .handle_irq = tegra20_mc_handle_irq, }; diff --git a/include/soc/tegra/mc.h b/include/soc/tegra/mc.h index a5ef84944a068..71ae37d3bedd7 100644 --- a/include/soc/tegra/mc.h +++ b/include/soc/tegra/mc.h @@ -96,7 +96,6 @@ struct tegra_smmu_soc { struct tegra_mc; struct tegra_smmu; -struct gart_device; #ifdef CONFIG_TEGRA_IOMMU_SMMU struct tegra_smmu *tegra_smmu_probe(struct device *dev, @@ -116,28 +115,6 @@ static inline void tegra_smmu_remove(struct tegra_smmu *smmu) } #endif -#ifdef CONFIG_TEGRA_IOMMU_GART -struct gart_device *tegra_gart_probe(struct device *dev, struct tegra_mc *mc); -int tegra_gart_suspend(struct gart_device *gart); -int tegra_gart_resume(struct gart_device *gart); -#else -static inline struct gart_device * -tegra_gart_probe(struct device *dev, struct tegra_mc *mc) -{ - return ERR_PTR(-ENODEV); -} - -static inline int tegra_gart_suspend(struct gart_device *gart) -{ - return -ENODEV; -} - -static inline int tegra_gart_resume(struct gart_device *gart) -{ - return -ENODEV; -} -#endif - struct tegra_mc_reset { const char *name; unsigned long id; @@ -185,8 +162,6 @@ struct tegra_mc_ops { */ int (*probe)(struct tegra_mc *mc); void (*remove)(struct tegra_mc *mc); - int (*suspend)(struct tegra_mc *mc); - int (*resume)(struct tegra_mc *mc); irqreturn_t (*handle_irq)(int irq, void *data); int (*probe_device)(struct tegra_mc *mc, struct device *dev); }; @@ -225,7 +200,6 @@ struct tegra_mc { struct tegra_bpmp *bpmp; struct device *dev; struct tegra_smmu *smmu; - struct gart_device *gart; void __iomem *regs; void __iomem *bcast_ch_regs; void __iomem **ch_regs; -- GitLab From 90057dc095dca023ad3e8cd5a129f392b543fb9e Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:40 -0300 Subject: [PATCH 0125/1451] iommu/mtk_iommu_v1: Implement an IDENTITY domain What mtk does during mtk_iommu_v1_set_platform_dma() is actually putting the iommu into identity mode. Make this available as a proper IDENTITY domain. The mtk_iommu_v1_def_domain_type() from commit 8bbe13f52cb7 ("iommu/mediatek-v1: Add def_domain_type") explains this was needed to allow probe_finalize() to be called, but now the IDENTITY domain will do the same job so change the returned def_domain_type. mkt_v1 is the only driver that returns IOMMU_DOMAIN_UNMANAGED from def_domain_type(). This allows the next patch to enforce an IDENTITY domain policy for this driver. Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/7-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/mtk_iommu_v1.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c index 8a0a5e5d049f4..cc3e7d53d33ad 100644 --- a/drivers/iommu/mtk_iommu_v1.c +++ b/drivers/iommu/mtk_iommu_v1.c @@ -319,11 +319,27 @@ static int mtk_iommu_v1_attach_device(struct iommu_domain *domain, struct device return 0; } -static void mtk_iommu_v1_set_platform_dma(struct device *dev) +static int mtk_iommu_v1_identity_attach(struct iommu_domain *identity_domain, + struct device *dev) { struct mtk_iommu_v1_data *data = dev_iommu_priv_get(dev); mtk_iommu_v1_config(data, dev, false); + return 0; +} + +static struct iommu_domain_ops mtk_iommu_v1_identity_ops = { + .attach_dev = mtk_iommu_v1_identity_attach, +}; + +static struct iommu_domain mtk_iommu_v1_identity_domain = { + .type = IOMMU_DOMAIN_IDENTITY, + .ops = &mtk_iommu_v1_identity_ops, +}; + +static void mtk_iommu_v1_set_platform_dma(struct device *dev) +{ + mtk_iommu_v1_identity_attach(&mtk_iommu_v1_identity_domain, dev); } static int mtk_iommu_v1_map(struct iommu_domain *domain, unsigned long iova, @@ -443,7 +459,7 @@ static int mtk_iommu_v1_create_mapping(struct device *dev, struct of_phandle_arg static int mtk_iommu_v1_def_domain_type(struct device *dev) { - return IOMMU_DOMAIN_UNMANAGED; + return IOMMU_DOMAIN_IDENTITY; } static struct iommu_device *mtk_iommu_v1_probe_device(struct device *dev) @@ -578,6 +594,7 @@ static int mtk_iommu_v1_hw_init(const struct mtk_iommu_v1_data *data) } static const struct iommu_ops mtk_iommu_v1_ops = { + .identity_domain = &mtk_iommu_v1_identity_domain, .domain_alloc = mtk_iommu_v1_domain_alloc, .probe_device = mtk_iommu_v1_probe_device, .probe_finalize = mtk_iommu_v1_probe_finalize, -- GitLab From 59ddce4418da483c932bc7a08b88d6ba14020e83 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:41 -0300 Subject: [PATCH 0126/1451] iommu: Reorganize iommu_get_default_domain_type() to respect def_domain_type() Except for dart (which forces IOMMU_DOMAIN_DMA) every driver returns 0 or IDENTITY from ops->def_domain_type(). The drivers that return IDENTITY have some kind of good reason, typically that quirky hardware really can't support anything other than IDENTITY. Arrange things so that if the driver says it needs IDENTITY then iommu_get_default_domain_type() either fails or returns IDENTITY. It will not ignore the driver's override to IDENTITY. Split the function into two steps, reducing the group device list to the driver's def_domain_type() and the untrusted flag. Then compute the result based on those two reduced variables. Fully reject combining untrusted with IDENTITY. Remove the debugging print on the iommu_group_store_type() failure path, userspace should not be able to trigger kernel prints. This makes the next patch cleaner that wants to force IDENTITY always for ARM_IOMMU because there is no support for DMA. Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/8-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 115 ++++++++++++++++++++++++++++-------------- 1 file changed, 78 insertions(+), 37 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 0e13e566581c2..9188eae61e929 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1718,19 +1718,6 @@ struct iommu_group *fsl_mc_device_group(struct device *dev) } EXPORT_SYMBOL_GPL(fsl_mc_device_group); -static int iommu_get_def_domain_type(struct device *dev) -{ - const struct iommu_ops *ops = dev_iommu_ops(dev); - - if (dev_is_pci(dev) && to_pci_dev(dev)->untrusted) - return IOMMU_DOMAIN_DMA; - - if (ops->def_domain_type) - return ops->def_domain_type(dev); - - return 0; -} - static struct iommu_domain * __iommu_group_alloc_default_domain(const struct bus_type *bus, struct iommu_group *group, int req_type) @@ -1740,6 +1727,23 @@ __iommu_group_alloc_default_domain(const struct bus_type *bus, return __iommu_domain_alloc(bus, req_type); } +/* + * Returns the iommu_ops for the devices in an iommu group. + * + * It is assumed that all devices in an iommu group are managed by a single + * IOMMU unit. Therefore, this returns the dev_iommu_ops of the first device + * in the group. + */ +static const struct iommu_ops *group_iommu_ops(struct iommu_group *group) +{ + struct group_device *device = + list_first_entry(&group->devices, struct group_device, list); + + lockdep_assert_held(&group->mutex); + + return dev_iommu_ops(device->dev); +} + /* * req_type of 0 means "auto" which means to select a domain based on * iommu_def_domain_type or what the driver actually supports. @@ -1820,40 +1824,77 @@ static int iommu_bus_notifier(struct notifier_block *nb, return 0; } -/* A target_type of 0 will select the best domain type and cannot fail */ +/* + * Combine the driver's chosen def_domain_type across all the devices in a + * group. Drivers must give a consistent result. + */ +static int iommu_get_def_domain_type(struct iommu_group *group, + struct device *dev, int cur_type) +{ + const struct iommu_ops *ops = group_iommu_ops(group); + int type; + + if (!ops->def_domain_type) + return cur_type; + + type = ops->def_domain_type(dev); + if (!type || cur_type == type) + return cur_type; + if (!cur_type) + return type; + + dev_err_ratelimited( + dev, + "IOMMU driver error, requesting conflicting def_domain_type, %s and %s, for devices in group %u.\n", + iommu_domain_type_str(cur_type), iommu_domain_type_str(type), + group->id); + + /* + * Try to recover, drivers are allowed to force IDENITY or DMA, IDENTITY + * takes precedence. + */ + if (type == IOMMU_DOMAIN_IDENTITY) + return type; + return cur_type; +} + +/* + * A target_type of 0 will select the best domain type. 0 can be returned in + * this case meaning the global default should be used. + */ static int iommu_get_default_domain_type(struct iommu_group *group, int target_type) { - int best_type = target_type; + struct device *untrusted = NULL; struct group_device *gdev; - struct device *last_dev; + int driver_type = 0; lockdep_assert_held(&group->mutex); - for_each_group_device(group, gdev) { - unsigned int type = iommu_get_def_domain_type(gdev->dev); - - if (best_type && type && best_type != type) { - if (target_type) { - dev_err_ratelimited( - gdev->dev, - "Device cannot be in %s domain\n", - iommu_domain_type_str(target_type)); - return -1; - } + driver_type = iommu_get_def_domain_type(group, gdev->dev, + driver_type); - dev_warn( - gdev->dev, - "Device needs domain type %s, but device %s in the same iommu group requires type %s - using default\n", - iommu_domain_type_str(type), dev_name(last_dev), - iommu_domain_type_str(best_type)); - return 0; + if (dev_is_pci(gdev->dev) && to_pci_dev(gdev->dev)->untrusted) + untrusted = gdev->dev; + } + + if (untrusted) { + if (driver_type && driver_type != IOMMU_DOMAIN_DMA) { + dev_err_ratelimited( + untrusted, + "Device is not trusted, but driver is overriding group %u to %s, refusing to probe.\n", + group->id, iommu_domain_type_str(driver_type)); + return -1; } - if (!best_type) - best_type = type; - last_dev = gdev->dev; + driver_type = IOMMU_DOMAIN_DMA; + } + + if (target_type) { + if (driver_type && target_type != driver_type) + return -1; + return target_type; } - return best_type; + return driver_type; } static void iommu_group_do_probe_finalize(struct device *dev) -- GitLab From e98befd010bd56b8b3f2afea2d600e30df023e6b Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:42 -0300 Subject: [PATCH 0127/1451] iommu: Allow an IDENTITY domain as the default_domain in ARM32 Even though dma-iommu.c and CONFIG_ARM_DMA_USE_IOMMU do approximately the same stuff, the way they relate to the IOMMU core is quiet different. dma-iommu.c expects the core code to setup an UNMANAGED domain (of type IOMMU_DOMAIN_DMA) and then configures itself to use that domain. This becomes the default_domain for the group. ARM_DMA_USE_IOMMU does not use the default_domain, instead it directly allocates an UNMANAGED domain and operates it just like an external driver. In this case group->default_domain is NULL. If the driver provides a global static identity_domain then automatically use it as the default_domain when in ARM_DMA_USE_IOMMU mode. This allows drivers that implemented default_domain == NULL as an IDENTITY translation to trivially get a properly labeled non-NULL default_domain on ARM32 configs. With this arrangment when ARM_DMA_USE_IOMMU wants to disconnect from the device the normal detach_domain flow will restore the IDENTITY domain as the default domain. Overall this makes attach_dev() of the IDENTITY domain called in the same places as detach_dev(). This effectively migrates these drivers to default_domain mode. For drivers that support ARM64 they will gain support for the IDENTITY translation mode for the dma_api and behave in a uniform way. Drivers use this by setting ops->identity_domain to a static singleton iommu_domain that implements the identity attach. If the core detects ARM_DMA_USE_IOMMU mode then it automatically attaches the IDENTITY domain during probe. Drivers can continue to prevent the use of DMA translation by returning IOMMU_DOMAIN_IDENTITY from def_domain_type, this will completely prevent IOMMU_DMA from running but will not impact ARM_DMA_USE_IOMMU. This allows removing the set_platform_dma_ops() from every remaining driver. Remove the set_platform_dma_ops from rockchip and mkt_v1 as all it does is set an existing global static identity domain. mkt_v1 does not support IOMMU_DOMAIN_DMA and it does not compile on ARM64 so this transformation is safe. Tested-by: Steven Price Tested-by: Marek Szyprowski Tested-by: Nicolin Chen Reviewed-by: Lu Baolu Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/9-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 21 ++++++++++++++++++++- drivers/iommu/mtk_iommu_v1.c | 12 ------------ drivers/iommu/rockchip-iommu.c | 10 ---------- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 9188eae61e929..1efd6351bbc2d 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1865,17 +1865,36 @@ static int iommu_get_def_domain_type(struct iommu_group *group, static int iommu_get_default_domain_type(struct iommu_group *group, int target_type) { + const struct iommu_ops *ops = group_iommu_ops(group); struct device *untrusted = NULL; struct group_device *gdev; int driver_type = 0; lockdep_assert_held(&group->mutex); + + /* + * ARM32 drivers supporting CONFIG_ARM_DMA_USE_IOMMU can declare an + * identity_domain and it will automatically become their default + * domain. Later on ARM_DMA_USE_IOMMU will install its UNMANAGED domain. + * Override the selection to IDENTITY if we are sure the driver supports + * it. + */ + if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) && ops->identity_domain) + driver_type = IOMMU_DOMAIN_IDENTITY; + for_each_group_device(group, gdev) { driver_type = iommu_get_def_domain_type(group, gdev->dev, driver_type); - if (dev_is_pci(gdev->dev) && to_pci_dev(gdev->dev)->untrusted) + if (dev_is_pci(gdev->dev) && to_pci_dev(gdev->dev)->untrusted) { + /* + * No ARM32 using systems will set untrusted, it cannot + * work. + */ + if (WARN_ON(IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU))) + return -1; untrusted = gdev->dev; + } } if (untrusted) { diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c index cc3e7d53d33ad..7c0c1d50df5f7 100644 --- a/drivers/iommu/mtk_iommu_v1.c +++ b/drivers/iommu/mtk_iommu_v1.c @@ -337,11 +337,6 @@ static struct iommu_domain mtk_iommu_v1_identity_domain = { .ops = &mtk_iommu_v1_identity_ops, }; -static void mtk_iommu_v1_set_platform_dma(struct device *dev) -{ - mtk_iommu_v1_identity_attach(&mtk_iommu_v1_identity_domain, dev); -} - static int mtk_iommu_v1_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t paddr, size_t pgsize, size_t pgcount, int prot, gfp_t gfp, size_t *mapped) @@ -457,11 +452,6 @@ static int mtk_iommu_v1_create_mapping(struct device *dev, struct of_phandle_arg return 0; } -static int mtk_iommu_v1_def_domain_type(struct device *dev) -{ - return IOMMU_DOMAIN_IDENTITY; -} - static struct iommu_device *mtk_iommu_v1_probe_device(struct device *dev) { struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); @@ -599,10 +589,8 @@ static const struct iommu_ops mtk_iommu_v1_ops = { .probe_device = mtk_iommu_v1_probe_device, .probe_finalize = mtk_iommu_v1_probe_finalize, .release_device = mtk_iommu_v1_release_device, - .def_domain_type = mtk_iommu_v1_def_domain_type, .device_group = generic_device_group, .pgsize_bitmap = MT2701_IOMMU_PAGE_SIZE, - .set_platform_dma_ops = mtk_iommu_v1_set_platform_dma, .owner = THIS_MODULE, .default_domain_ops = &(const struct iommu_domain_ops) { .attach_dev = mtk_iommu_v1_attach_device, diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index 033678f2f8b3a..a582525d36f8c 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -998,13 +998,6 @@ static struct iommu_domain rk_identity_domain = { .ops = &rk_identity_ops, }; -#ifdef CONFIG_ARM -static void rk_iommu_set_platform_dma(struct device *dev) -{ - WARN_ON(rk_iommu_identity_attach(&rk_identity_domain, dev)); -} -#endif - static int rk_iommu_attach_device(struct iommu_domain *domain, struct device *dev) { @@ -1183,9 +1176,6 @@ static const struct iommu_ops rk_iommu_ops = { .probe_device = rk_iommu_probe_device, .release_device = rk_iommu_release_device, .device_group = rk_iommu_device_group, -#ifdef CONFIG_ARM - .set_platform_dma_ops = rk_iommu_set_platform_dma, -#endif .pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP, .of_xlate = rk_iommu_of_xlate, .default_domain_ops = &(const struct iommu_domain_ops) { -- GitLab From b3d14960e629f9ee8c82f8feb211ae43e1cb3246 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:43 -0300 Subject: [PATCH 0128/1451] iommu/exynos: Implement an IDENTITY domain What exynos calls exynos_iommu_detach_device is actually putting the iommu into identity mode. Move to the new core support for ARM_DMA_USE_IOMMU by defining ops->identity_domain. Tested-by: Marek Szyprowski Acked-by: Marek Szyprowski Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/10-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/exynos-iommu.c | 66 +++++++++++++++++------------------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index c275fe71c4db3..5e12b85dfe870 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -24,6 +24,7 @@ typedef u32 sysmmu_iova_t; typedef u32 sysmmu_pte_t; +static struct iommu_domain exynos_identity_domain; /* We do not consider super section mapping (16MB) */ #define SECT_ORDER 20 @@ -829,7 +830,7 @@ static int __maybe_unused exynos_sysmmu_suspend(struct device *dev) struct exynos_iommu_owner *owner = dev_iommu_priv_get(master); mutex_lock(&owner->rpm_lock); - if (data->domain) { + if (&data->domain->domain != &exynos_identity_domain) { dev_dbg(data->sysmmu, "saving state\n"); __sysmmu_disable(data); } @@ -847,7 +848,7 @@ static int __maybe_unused exynos_sysmmu_resume(struct device *dev) struct exynos_iommu_owner *owner = dev_iommu_priv_get(master); mutex_lock(&owner->rpm_lock); - if (data->domain) { + if (&data->domain->domain != &exynos_identity_domain) { dev_dbg(data->sysmmu, "restoring state\n"); __sysmmu_enable(data); } @@ -980,17 +981,20 @@ static void exynos_iommu_domain_free(struct iommu_domain *iommu_domain) kfree(domain); } -static void exynos_iommu_detach_device(struct iommu_domain *iommu_domain, - struct device *dev) +static int exynos_iommu_identity_attach(struct iommu_domain *identity_domain, + struct device *dev) { - struct exynos_iommu_domain *domain = to_exynos_domain(iommu_domain); struct exynos_iommu_owner *owner = dev_iommu_priv_get(dev); - phys_addr_t pagetable = virt_to_phys(domain->pgtable); + struct exynos_iommu_domain *domain; + phys_addr_t pagetable; struct sysmmu_drvdata *data, *next; unsigned long flags; - if (!has_sysmmu(dev) || owner->domain != iommu_domain) - return; + if (owner->domain == identity_domain) + return 0; + + domain = to_exynos_domain(owner->domain); + pagetable = virt_to_phys(domain->pgtable); mutex_lock(&owner->rpm_lock); @@ -1009,15 +1013,25 @@ static void exynos_iommu_detach_device(struct iommu_domain *iommu_domain, list_del_init(&data->domain_node); spin_unlock(&data->lock); } - owner->domain = NULL; + owner->domain = identity_domain; spin_unlock_irqrestore(&domain->lock, flags); mutex_unlock(&owner->rpm_lock); - dev_dbg(dev, "%s: Detached IOMMU with pgtable %pa\n", __func__, - &pagetable); + dev_dbg(dev, "%s: Restored IOMMU to IDENTITY from pgtable %pa\n", + __func__, &pagetable); + return 0; } +static struct iommu_domain_ops exynos_identity_ops = { + .attach_dev = exynos_iommu_identity_attach, +}; + +static struct iommu_domain exynos_identity_domain = { + .type = IOMMU_DOMAIN_IDENTITY, + .ops = &exynos_identity_ops, +}; + static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain, struct device *dev) { @@ -1026,12 +1040,11 @@ static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain, struct sysmmu_drvdata *data; phys_addr_t pagetable = virt_to_phys(domain->pgtable); unsigned long flags; + int err; - if (!has_sysmmu(dev)) - return -ENODEV; - - if (owner->domain) - exynos_iommu_detach_device(owner->domain, dev); + err = exynos_iommu_identity_attach(&exynos_identity_domain, dev); + if (err) + return err; mutex_lock(&owner->rpm_lock); @@ -1407,26 +1420,12 @@ static struct iommu_device *exynos_iommu_probe_device(struct device *dev) return &data->iommu; } -static void exynos_iommu_set_platform_dma(struct device *dev) -{ - struct exynos_iommu_owner *owner = dev_iommu_priv_get(dev); - - if (owner->domain) { - struct iommu_group *group = iommu_group_get(dev); - - if (group) { - exynos_iommu_detach_device(owner->domain, dev); - iommu_group_put(group); - } - } -} - static void exynos_iommu_release_device(struct device *dev) { struct exynos_iommu_owner *owner = dev_iommu_priv_get(dev); struct sysmmu_drvdata *data; - exynos_iommu_set_platform_dma(dev); + WARN_ON(exynos_iommu_identity_attach(&exynos_identity_domain, dev)); list_for_each_entry(data, &owner->controllers, owner_node) device_link_del(data->link); @@ -1457,6 +1456,7 @@ static int exynos_iommu_of_xlate(struct device *dev, INIT_LIST_HEAD(&owner->controllers); mutex_init(&owner->rpm_lock); + owner->domain = &exynos_identity_domain; dev_iommu_priv_set(dev, owner); } @@ -1471,11 +1471,9 @@ static int exynos_iommu_of_xlate(struct device *dev, } static const struct iommu_ops exynos_iommu_ops = { + .identity_domain = &exynos_identity_domain, .domain_alloc = exynos_iommu_domain_alloc, .device_group = generic_device_group, -#ifdef CONFIG_ARM - .set_platform_dma_ops = exynos_iommu_set_platform_dma, -#endif .probe_device = exynos_iommu_probe_device, .release_device = exynos_iommu_release_device, .pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE, -- GitLab From c8cc2655cc6c7ff832827ad5bc1a8f3df165706d Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:44 -0300 Subject: [PATCH 0129/1451] iommu/tegra-smmu: Implement an IDENTITY domain What tegra-smmu does during tegra_smmu_set_platform_dma() is actually putting the iommu into identity mode. Move to the new core support for ARM_DMA_USE_IOMMU by defining ops->identity_domain. Reviewed-by: Lu Baolu Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/11-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-smmu.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index e445f80d02263..80481e1ba561b 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -511,23 +511,39 @@ static int tegra_smmu_attach_dev(struct iommu_domain *domain, return err; } -static void tegra_smmu_set_platform_dma(struct device *dev) +static int tegra_smmu_identity_attach(struct iommu_domain *identity_domain, + struct device *dev) { struct iommu_domain *domain = iommu_get_domain_for_dev(dev); struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); - struct tegra_smmu_as *as = to_smmu_as(domain); - struct tegra_smmu *smmu = as->smmu; + struct tegra_smmu_as *as; + struct tegra_smmu *smmu; unsigned int index; if (!fwspec) - return; + return -ENODEV; + + if (domain == identity_domain || !domain) + return 0; + as = to_smmu_as(domain); + smmu = as->smmu; for (index = 0; index < fwspec->num_ids; index++) { tegra_smmu_disable(smmu, fwspec->ids[index], as->id); tegra_smmu_as_unprepare(smmu, as); } + return 0; } +static struct iommu_domain_ops tegra_smmu_identity_ops = { + .attach_dev = tegra_smmu_identity_attach, +}; + +static struct iommu_domain tegra_smmu_identity_domain = { + .type = IOMMU_DOMAIN_IDENTITY, + .ops = &tegra_smmu_identity_ops, +}; + static void tegra_smmu_set_pde(struct tegra_smmu_as *as, unsigned long iova, u32 value) { @@ -962,11 +978,22 @@ static int tegra_smmu_of_xlate(struct device *dev, return iommu_fwspec_add_ids(dev, &id, 1); } +static int tegra_smmu_def_domain_type(struct device *dev) +{ + /* + * FIXME: For now we want to run all translation in IDENTITY mode, due + * to some device quirks. Better would be to just quirk the troubled + * devices. + */ + return IOMMU_DOMAIN_IDENTITY; +} + static const struct iommu_ops tegra_smmu_ops = { + .identity_domain = &tegra_smmu_identity_domain, + .def_domain_type = &tegra_smmu_def_domain_type, .domain_alloc = tegra_smmu_domain_alloc, .probe_device = tegra_smmu_probe_device, .device_group = tegra_smmu_device_group, - .set_platform_dma_ops = tegra_smmu_set_platform_dma, .of_xlate = tegra_smmu_of_xlate, .pgsize_bitmap = SZ_4K, .default_domain_ops = &(const struct iommu_domain_ops) { -- GitLab From f128094f347f578279e551488796d0a0067cbdff Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:45 -0300 Subject: [PATCH 0130/1451] iommu/tegra-smmu: Support DMA domains in tegra All ARM64 iommu drivers should support IOMMU_DOMAIN_DMA to enable dma-iommu.c. tegra is blocking dma-iommu usage, and also default_domain's, because it wants an identity translation. This is needed for some device quirk. The correct way to do this is to support IDENTITY domains and use ops->def_domain_type() to return IOMMU_DOMAIN_IDENTITY for only the quirky devices. Add support for IOMMU_DOMAIN_DMA and force IOMMU_DOMAIN_IDENTITY mode for everything so no behavior changes. Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/12-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-smmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 80481e1ba561b..b91ad1b5a20d3 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -276,7 +276,7 @@ static struct iommu_domain *tegra_smmu_domain_alloc(unsigned type) { struct tegra_smmu_as *as; - if (type != IOMMU_DOMAIN_UNMANAGED) + if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA) return NULL; as = kzalloc(sizeof(*as), GFP_KERNEL); -- GitLab From bbe39b76330ecf64f8b3f45cdf8bacbbb7f390c9 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:46 -0300 Subject: [PATCH 0131/1451] iommu/omap: Implement an IDENTITY domain What omap does during omap_iommu_set_platform_dma() is actually putting the iommu into identity mode. Move to the new core support for ARM_DMA_USE_IOMMU by defining ops->identity_domain. This driver does not support IOMMU_DOMAIN_DMA, however it cannot be compiled on ARM64 either. Most likely it is fine to support dma-iommu.c Reviewed-by: Lu Baolu Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/13-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/omap-iommu.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index 537e402f9bba9..34340ef15241b 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -1555,16 +1555,31 @@ static void _omap_iommu_detach_dev(struct omap_iommu_domain *omap_domain, omap_domain->dev = NULL; } -static void omap_iommu_set_platform_dma(struct device *dev) +static int omap_iommu_identity_attach(struct iommu_domain *identity_domain, + struct device *dev) { struct iommu_domain *domain = iommu_get_domain_for_dev(dev); - struct omap_iommu_domain *omap_domain = to_omap_domain(domain); + struct omap_iommu_domain *omap_domain; + if (domain == identity_domain || !domain) + return 0; + + omap_domain = to_omap_domain(domain); spin_lock(&omap_domain->lock); _omap_iommu_detach_dev(omap_domain, dev); spin_unlock(&omap_domain->lock); + return 0; } +static struct iommu_domain_ops omap_iommu_identity_ops = { + .attach_dev = omap_iommu_identity_attach, +}; + +static struct iommu_domain omap_iommu_identity_domain = { + .type = IOMMU_DOMAIN_IDENTITY, + .ops = &omap_iommu_identity_ops, +}; + static struct iommu_domain *omap_iommu_domain_alloc(unsigned type) { struct omap_iommu_domain *omap_domain; @@ -1732,11 +1747,11 @@ static struct iommu_group *omap_iommu_device_group(struct device *dev) } static const struct iommu_ops omap_iommu_ops = { + .identity_domain = &omap_iommu_identity_domain, .domain_alloc = omap_iommu_domain_alloc, .probe_device = omap_iommu_probe_device, .release_device = omap_iommu_release_device, .device_group = omap_iommu_device_group, - .set_platform_dma_ops = omap_iommu_set_platform_dma, .pgsize_bitmap = OMAP_IOMMU_PGSIZES, .default_domain_ops = &(const struct iommu_domain_ops) { .attach_dev = omap_iommu_attach_dev, -- GitLab From 78fc30b4bb3540c88edd19c36d0a72bb0dd02d0b Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:47 -0300 Subject: [PATCH 0132/1451] iommu/msm: Implement an IDENTITY domain What msm does during msm_iommu_set_platform_dma() is actually putting the iommu into identity mode. Move to the new core support for ARM_DMA_USE_IOMMU by defining ops->identity_domain. This driver does not support IOMMU_DOMAIN_DMA, however it cannot be compiled on ARM64 either. Most likely it is fine to support dma-iommu.c Reviewed-by: Lu Baolu Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/14-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/msm_iommu.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c index 79d89bad5132b..26ed81cfeee89 100644 --- a/drivers/iommu/msm_iommu.c +++ b/drivers/iommu/msm_iommu.c @@ -443,15 +443,20 @@ static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev) return ret; } -static void msm_iommu_set_platform_dma(struct device *dev) +static int msm_iommu_identity_attach(struct iommu_domain *identity_domain, + struct device *dev) { struct iommu_domain *domain = iommu_get_domain_for_dev(dev); - struct msm_priv *priv = to_msm_priv(domain); + struct msm_priv *priv; unsigned long flags; struct msm_iommu_dev *iommu; struct msm_iommu_ctx_dev *master; - int ret; + int ret = 0; + + if (domain == identity_domain || !domain) + return 0; + priv = to_msm_priv(domain); free_io_pgtable_ops(priv->iop); spin_lock_irqsave(&msm_iommu_lock, flags); @@ -468,8 +473,18 @@ static void msm_iommu_set_platform_dma(struct device *dev) } fail: spin_unlock_irqrestore(&msm_iommu_lock, flags); + return ret; } +static struct iommu_domain_ops msm_iommu_identity_ops = { + .attach_dev = msm_iommu_identity_attach, +}; + +static struct iommu_domain msm_iommu_identity_domain = { + .type = IOMMU_DOMAIN_IDENTITY, + .ops = &msm_iommu_identity_ops, +}; + static int msm_iommu_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t pa, size_t pgsize, size_t pgcount, int prot, gfp_t gfp, size_t *mapped) @@ -675,10 +690,10 @@ irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id) } static struct iommu_ops msm_iommu_ops = { + .identity_domain = &msm_iommu_identity_domain, .domain_alloc = msm_iommu_domain_alloc, .probe_device = msm_iommu_probe_device, .device_group = generic_device_group, - .set_platform_dma_ops = msm_iommu_set_platform_dma, .pgsize_bitmap = MSM_IOMMU_PGSIZES, .of_xlate = qcom_iommu_of_xlate, .default_domain_ops = &(const struct iommu_domain_ops) { -- GitLab From 24b1d476167df3e30c7a53b67765bf3c787c5160 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:48 -0300 Subject: [PATCH 0133/1451] iommu: Remove ops->set_platform_dma_ops() All drivers are now using IDENTITY or PLATFORM domains for what this did, we can remove it now. It is no longer possible to attach to a NULL domain. Tested-by: Heiko Stuebner Tested-by: Niklas Schnelle Tested-by: Steven Price Tested-by: Marek Szyprowski Tested-by: Nicolin Chen Reviewed-by: Lu Baolu Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/15-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 30 +++++------------------------- include/linux/iommu.h | 4 ---- 2 files changed, 5 insertions(+), 29 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 1efd6351bbc2d..42a4585dd76da 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -2351,21 +2351,8 @@ static int __iommu_group_set_domain_internal(struct iommu_group *group, if (group->domain == new_domain) return 0; - /* - * New drivers should support default domains, so set_platform_dma() - * op will never be called. Otherwise the NULL domain represents some - * platform specific behavior. - */ - if (!new_domain) { - for_each_group_device(group, gdev) { - const struct iommu_ops *ops = dev_iommu_ops(gdev->dev); - - if (!WARN_ON(!ops->set_platform_dma_ops)) - ops->set_platform_dma_ops(gdev->dev); - } - group->domain = NULL; - return 0; - } + if (WARN_ON(!new_domain)) + return -EINVAL; /* * Changing the domain is done by calling attach_dev() on the new @@ -2401,19 +2388,15 @@ static int __iommu_group_set_domain_internal(struct iommu_group *group, */ last_gdev = gdev; for_each_group_device(group, gdev) { - const struct iommu_ops *ops = dev_iommu_ops(gdev->dev); - /* - * If set_platform_dma_ops is not present a NULL domain can - * happen only for first probe, in which case we leave - * group->domain as NULL and let release clean everything up. + * A NULL domain can happen only for first probe, in which case + * we leave group->domain as NULL and let release clean + * everything up. */ if (group->domain) WARN_ON(__iommu_device_set_domain( group, gdev->dev, group->domain, IOMMU_SET_DOMAIN_MUST_SUCCEED)); - else if (ops->set_platform_dma_ops) - ops->set_platform_dma_ops(gdev->dev); if (gdev == last_gdev) break; } @@ -3036,9 +3019,6 @@ static int iommu_setup_default_domain(struct iommu_group *group, /* * There are still some drivers which don't support default domains, so * we ignore the failure and leave group->default_domain NULL. - * - * We assume that the iommu driver starts up the device in - * 'set_platform_dma_ops' mode if it does not support default domains. */ dom = iommu_group_alloc_default_domain(group, req_type); if (!dom) { diff --git a/include/linux/iommu.h b/include/linux/iommu.h index a05480be05fd0..511dfeea52721 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -243,9 +243,6 @@ struct iommu_iotlb_gather { * @release_device: Remove device from iommu driver handling * @probe_finalize: Do final setup work after the device is added to an IOMMU * group and attached to the groups domain - * @set_platform_dma_ops: Returning control back to the platform DMA ops. This op - * is to support old IOMMU drivers, new drivers should use - * default domains, and the common IOMMU DMA ops. * @device_group: find iommu group for a particular device * @get_resv_regions: Request list of reserved regions for a device * @of_xlate: add OF master IDs to iommu grouping @@ -280,7 +277,6 @@ struct iommu_ops { struct iommu_device *(*probe_device)(struct device *dev); void (*release_device)(struct device *dev); void (*probe_finalize)(struct device *dev); - void (*set_platform_dma_ops)(struct device *dev); struct iommu_group *(*device_group)(struct device *dev); /* Request/Free a list of reserved regions for a device */ -- GitLab From 786478a90294ea5b149ed1156a43e82d63ea61ff Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:49 -0300 Subject: [PATCH 0134/1451] iommu/qcom_iommu: Add an IOMMU_IDENTITIY_DOMAIN This brings back the ops->detach_dev() code that commit 1b932ceddd19 ("iommu: Remove detach_dev callbacks") deleted and turns it into an IDENTITY domain. Reviewed-by: Lu Baolu Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/16-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/arm/arm-smmu/qcom_iommu.c | 39 +++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c index 775a3cbaff4ed..bc45d18f350cb 100644 --- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c +++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c @@ -400,6 +400,44 @@ static int qcom_iommu_attach_dev(struct iommu_domain *domain, struct device *dev return 0; } +static int qcom_iommu_identity_attach(struct iommu_domain *identity_domain, + struct device *dev) +{ + struct iommu_domain *domain = iommu_get_domain_for_dev(dev); + struct qcom_iommu_domain *qcom_domain; + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); + struct qcom_iommu_dev *qcom_iommu = to_iommu(dev); + unsigned int i; + + if (domain == identity_domain || !domain) + return 0; + + qcom_domain = to_qcom_iommu_domain(domain); + if (WARN_ON(!qcom_domain->iommu)) + return -EINVAL; + + pm_runtime_get_sync(qcom_iommu->dev); + for (i = 0; i < fwspec->num_ids; i++) { + struct qcom_iommu_ctx *ctx = to_ctx(qcom_domain, fwspec->ids[i]); + + /* Disable the context bank: */ + iommu_writel(ctx, ARM_SMMU_CB_SCTLR, 0); + + ctx->domain = NULL; + } + pm_runtime_put_sync(qcom_iommu->dev); + return 0; +} + +static struct iommu_domain_ops qcom_iommu_identity_ops = { + .attach_dev = qcom_iommu_identity_attach, +}; + +static struct iommu_domain qcom_iommu_identity_domain = { + .type = IOMMU_DOMAIN_IDENTITY, + .ops = &qcom_iommu_identity_ops, +}; + static int qcom_iommu_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t paddr, size_t pgsize, size_t pgcount, int prot, gfp_t gfp, size_t *mapped) @@ -565,6 +603,7 @@ static int qcom_iommu_of_xlate(struct device *dev, struct of_phandle_args *args) } static const struct iommu_ops qcom_iommu_ops = { + .identity_domain = &qcom_iommu_identity_domain, .capable = qcom_iommu_capable, .domain_alloc = qcom_iommu_domain_alloc, .probe_device = qcom_iommu_probe_device, -- GitLab From 666c9f1ef7fa9330ea041aba36658aeb48145846 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:50 -0300 Subject: [PATCH 0135/1451] iommu/ipmmu: Add an IOMMU_IDENTITIY_DOMAIN This brings back the ops->detach_dev() code that commit 1b932ceddd19 ("iommu: Remove detach_dev callbacks") deleted and turns it into an IDENTITY domain. Also reverts commit 584d334b1393 ("iommu/ipmmu-vmsa: Remove ipmmu_utlb_disable()") Reviewed-by: Lu Baolu Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/17-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/ipmmu-vmsa.c | 43 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index 65ff69477c43e..04830d3931d23 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -295,6 +295,18 @@ static void ipmmu_utlb_enable(struct ipmmu_vmsa_domain *domain, mmu->utlb_ctx[utlb] = domain->context_id; } +/* + * Disable MMU translation for the microTLB. + */ +static void ipmmu_utlb_disable(struct ipmmu_vmsa_domain *domain, + unsigned int utlb) +{ + struct ipmmu_vmsa_device *mmu = domain->mmu; + + ipmmu_imuctr_write(mmu, utlb, 0); + mmu->utlb_ctx[utlb] = IPMMU_CTX_INVALID; +} + static void ipmmu_tlb_flush_all(void *cookie) { struct ipmmu_vmsa_domain *domain = cookie; @@ -627,6 +639,36 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain, return 0; } +static int ipmmu_iommu_identity_attach(struct iommu_domain *identity_domain, + struct device *dev) +{ + struct iommu_domain *io_domain = iommu_get_domain_for_dev(dev); + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); + struct ipmmu_vmsa_domain *domain; + unsigned int i; + + if (io_domain == identity_domain || !io_domain) + return 0; + + domain = to_vmsa_domain(io_domain); + for (i = 0; i < fwspec->num_ids; ++i) + ipmmu_utlb_disable(domain, fwspec->ids[i]); + + /* + * TODO: Optimize by disabling the context when no device is attached. + */ + return 0; +} + +static struct iommu_domain_ops ipmmu_iommu_identity_ops = { + .attach_dev = ipmmu_iommu_identity_attach, +}; + +static struct iommu_domain ipmmu_iommu_identity_domain = { + .type = IOMMU_DOMAIN_IDENTITY, + .ops = &ipmmu_iommu_identity_ops, +}; + static int ipmmu_map(struct iommu_domain *io_domain, unsigned long iova, phys_addr_t paddr, size_t pgsize, size_t pgcount, int prot, gfp_t gfp, size_t *mapped) @@ -849,6 +891,7 @@ static struct iommu_group *ipmmu_find_group(struct device *dev) } static const struct iommu_ops ipmmu_ops = { + .identity_domain = &ipmmu_iommu_identity_domain, .domain_alloc = ipmmu_domain_alloc, .probe_device = ipmmu_probe_device, .release_device = ipmmu_release_device, -- GitLab From b01b12573837f237cec13b9ddf8e5e623ee6f981 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:51 -0300 Subject: [PATCH 0136/1451] iommu/mtk_iommu: Add an IOMMU_IDENTITIY_DOMAIN This brings back the ops->detach_dev() code that commit 1b932ceddd19 ("iommu: Remove detach_dev callbacks") deleted and turns it into an IDENTITY domain. Reviewed-by: Lu Baolu Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/18-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/mtk_iommu.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index 640275873a271..164f9759e1c03 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -777,6 +777,28 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain, return ret; } +static int mtk_iommu_identity_attach(struct iommu_domain *identity_domain, + struct device *dev) +{ + struct iommu_domain *domain = iommu_get_domain_for_dev(dev); + struct mtk_iommu_data *data = dev_iommu_priv_get(dev); + + if (domain == identity_domain || !domain) + return 0; + + mtk_iommu_config(data, dev, false, 0); + return 0; +} + +static struct iommu_domain_ops mtk_iommu_identity_ops = { + .attach_dev = mtk_iommu_identity_attach, +}; + +static struct iommu_domain mtk_iommu_identity_domain = { + .type = IOMMU_DOMAIN_IDENTITY, + .ops = &mtk_iommu_identity_ops, +}; + static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t paddr, size_t pgsize, size_t pgcount, int prot, gfp_t gfp, size_t *mapped) @@ -996,6 +1018,7 @@ static void mtk_iommu_get_resv_regions(struct device *dev, } static const struct iommu_ops mtk_iommu_ops = { + .identity_domain = &mtk_iommu_identity_domain, .domain_alloc = mtk_iommu_domain_alloc, .probe_device = mtk_iommu_probe_device, .release_device = mtk_iommu_release_device, -- GitLab From 5b167dea64a3fb72907e33f30211d4a5711076f1 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:52 -0300 Subject: [PATCH 0137/1451] iommu/sun50i: Add an IOMMU_IDENTITIY_DOMAIN Prior to commit 1b932ceddd19 ("iommu: Remove detach_dev callbacks") the sun50i_iommu_detach_device() function was being called by ops->detach_dev(). This is an IDENTITY domain so convert sun50i_iommu_detach_device() into sun50i_iommu_identity_attach() and a full IDENTITY domain and thus hook it back up the same was as the old ops->detach_dev(). Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/19-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/sun50i-iommu.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/iommu/sun50i-iommu.c b/drivers/iommu/sun50i-iommu.c index 74c5cb93e9002..0bf08b120cf10 100644 --- a/drivers/iommu/sun50i-iommu.c +++ b/drivers/iommu/sun50i-iommu.c @@ -757,21 +757,32 @@ static void sun50i_iommu_detach_domain(struct sun50i_iommu *iommu, iommu->domain = NULL; } -static void sun50i_iommu_detach_device(struct iommu_domain *domain, - struct device *dev) +static int sun50i_iommu_identity_attach(struct iommu_domain *identity_domain, + struct device *dev) { - struct sun50i_iommu_domain *sun50i_domain = to_sun50i_domain(domain); struct sun50i_iommu *iommu = dev_iommu_priv_get(dev); + struct sun50i_iommu_domain *sun50i_domain; dev_dbg(dev, "Detaching from IOMMU domain\n"); - if (iommu->domain != domain) - return; + if (iommu->domain == identity_domain) + return 0; + sun50i_domain = to_sun50i_domain(iommu->domain); if (refcount_dec_and_test(&sun50i_domain->refcnt)) sun50i_iommu_detach_domain(iommu, sun50i_domain); + return 0; } +static struct iommu_domain_ops sun50i_iommu_identity_ops = { + .attach_dev = sun50i_iommu_identity_attach, +}; + +static struct iommu_domain sun50i_iommu_identity_domain = { + .type = IOMMU_DOMAIN_IDENTITY, + .ops = &sun50i_iommu_identity_ops, +}; + static int sun50i_iommu_attach_device(struct iommu_domain *domain, struct device *dev) { @@ -789,8 +800,7 @@ static int sun50i_iommu_attach_device(struct iommu_domain *domain, if (iommu->domain == domain) return 0; - if (iommu->domain) - sun50i_iommu_detach_device(iommu->domain, dev); + sun50i_iommu_identity_attach(&sun50i_iommu_identity_domain, dev); sun50i_iommu_attach_domain(iommu, sun50i_domain); @@ -827,6 +837,7 @@ static int sun50i_iommu_of_xlate(struct device *dev, } static const struct iommu_ops sun50i_iommu_ops = { + .identity_domain = &sun50i_iommu_identity_domain, .pgsize_bitmap = SZ_4K, .device_group = sun50i_iommu_device_group, .domain_alloc = sun50i_iommu_domain_alloc, @@ -985,6 +996,7 @@ static int sun50i_iommu_probe(struct platform_device *pdev) if (!iommu) return -ENOMEM; spin_lock_init(&iommu->iommu_lock); + iommu->domain = &sun50i_iommu_identity_domain; platform_set_drvdata(pdev, iommu); iommu->dev = &pdev->dev; -- GitLab From 98ac73f99bc44fba8a14252ffb0bad02459f7008 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:53 -0300 Subject: [PATCH 0138/1451] iommu: Require a default_domain for all iommu drivers At this point every iommu driver will cause a default_domain to be selected, so we can finally remove this gap from the core code. The following table explains what each driver supports and what the resulting default_domain will be: ops->defaut_domain IDENTITY DMA PLATFORM v ARM32 dma-iommu ARCH amd/iommu.c Y Y N/A either apple-dart.c Y Y N/A either arm-smmu.c Y Y IDENTITY either qcom_iommu.c G Y IDENTITY either arm-smmu-v3.c Y Y N/A either exynos-iommu.c G Y IDENTITY either fsl_pamu_domain.c Y Y N/A N/A PLATFORM intel/iommu.c Y Y N/A either ipmmu-vmsa.c G Y IDENTITY either msm_iommu.c G IDENTITY N/A mtk_iommu.c G Y IDENTITY either mtk_iommu_v1.c G IDENTITY N/A omap-iommu.c G IDENTITY N/A rockchip-iommu.c G Y IDENTITY either s390-iommu.c Y Y N/A N/A PLATFORM sprd-iommu.c Y N/A DMA sun50i-iommu.c G Y IDENTITY either tegra-smmu.c G Y IDENTITY IDENTITY virtio-iommu.c Y Y N/A either spapr Y Y N/A N/A PLATFORM * G means ops->identity_domain is used * N/A means the driver will not compile in this configuration ARM32 drivers select an IDENTITY default domain through either the ops->identity_domain or directly requesting an IDENTIY domain through alloc_domain(). In ARM64 mode tegra-smmu will still block the use of dma-iommu.c and forces an IDENTITY domain. S390 uses a PLATFORM domain to represent when the dma_ops are set to the s390 iommu code. fsl_pamu uses an PLATFORM domain. POWER SPAPR uses PLATFORM and blocking to enable its weird VFIO mode. The x86 drivers continue unchanged. After this patch group->default_domain is only NULL for a short period during bus iommu probing while all the groups are constituted. Otherwise it is always !NULL. This completes changing the iommu subsystem driver contract to a system where the current iommu_domain always represents some form of translation and the driver is continuously asserting a definable translation mode. It resolves the confusion that the original ops->detach_dev() caused around what translation, exactly, is the IOMMU performing after detach. There were at least three different answers to that question in the tree, they are all now clearly named with domain types. Tested-by: Heiko Stuebner Tested-by: Niklas Schnelle Tested-by: Steven Price Tested-by: Marek Szyprowski Tested-by: Nicolin Chen Reviewed-by: Lu Baolu Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/20-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 42a4585dd76da..cfb597751f5ba 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1865,7 +1865,6 @@ static int iommu_get_def_domain_type(struct iommu_group *group, static int iommu_get_default_domain_type(struct iommu_group *group, int target_type) { - const struct iommu_ops *ops = group_iommu_ops(group); struct device *untrusted = NULL; struct group_device *gdev; int driver_type = 0; @@ -1876,11 +1875,13 @@ static int iommu_get_default_domain_type(struct iommu_group *group, * ARM32 drivers supporting CONFIG_ARM_DMA_USE_IOMMU can declare an * identity_domain and it will automatically become their default * domain. Later on ARM_DMA_USE_IOMMU will install its UNMANAGED domain. - * Override the selection to IDENTITY if we are sure the driver supports - * it. + * Override the selection to IDENTITY. */ - if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) && ops->identity_domain) + if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) { + static_assert(!(IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) && + IS_ENABLED(CONFIG_IOMMU_DMA))); driver_type = IOMMU_DOMAIN_IDENTITY; + } for_each_group_device(group, gdev) { driver_type = iommu_get_def_domain_type(group, gdev->dev, @@ -3016,18 +3017,9 @@ static int iommu_setup_default_domain(struct iommu_group *group, if (req_type < 0) return -EINVAL; - /* - * There are still some drivers which don't support default domains, so - * we ignore the failure and leave group->default_domain NULL. - */ dom = iommu_group_alloc_default_domain(group, req_type); - if (!dom) { - /* Once in default_domain mode we never leave */ - if (group->default_domain) - return -ENODEV; - group->default_domain = NULL; - return 0; - } + if (!dom) + return -ENODEV; if (group->default_domain == dom) return 0; -- GitLab From 8359cf39acba72606736f453f54432ac9dc28523 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:54 -0300 Subject: [PATCH 0139/1451] iommu: Add __iommu_group_domain_alloc() Allocate a domain from a group. Automatically obtains the iommu_ops to use from the device list of the group. Convert the internal callers to use it. Tested-by: Steven Price Tested-by: Marek Szyprowski Tested-by: Nicolin Chen Reviewed-by: Lu Baolu Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/21-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 59 +++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index cfb597751f5ba..38856d542afc3 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -96,8 +96,8 @@ static const char * const iommu_group_resv_type_string[] = { static int iommu_bus_notifier(struct notifier_block *nb, unsigned long action, void *data); static void iommu_release_device(struct device *dev); -static struct iommu_domain *__iommu_domain_alloc(const struct bus_type *bus, - unsigned type); +static struct iommu_domain * +__iommu_group_domain_alloc(struct iommu_group *group, unsigned int type); static int __iommu_attach_device(struct iommu_domain *domain, struct device *dev); static int __iommu_attach_group(struct iommu_domain *domain, @@ -1719,12 +1719,11 @@ struct iommu_group *fsl_mc_device_group(struct device *dev) EXPORT_SYMBOL_GPL(fsl_mc_device_group); static struct iommu_domain * -__iommu_group_alloc_default_domain(const struct bus_type *bus, - struct iommu_group *group, int req_type) +__iommu_group_alloc_default_domain(struct iommu_group *group, int req_type) { if (group->default_domain && group->default_domain->type == req_type) return group->default_domain; - return __iommu_domain_alloc(bus, req_type); + return __iommu_group_domain_alloc(group, req_type); } /* @@ -1751,9 +1750,7 @@ static const struct iommu_ops *group_iommu_ops(struct iommu_group *group) static struct iommu_domain * iommu_group_alloc_default_domain(struct iommu_group *group, int req_type) { - const struct bus_type *bus = - list_first_entry(&group->devices, struct group_device, list) - ->dev->bus; + const struct iommu_ops *ops = group_iommu_ops(group); struct iommu_domain *dom; lockdep_assert_held(&group->mutex); @@ -1763,24 +1760,24 @@ iommu_group_alloc_default_domain(struct iommu_group *group, int req_type) * domain. This should always be either an IDENTITY/BLOCKED/PLATFORM * domain. Do not use in new drivers. */ - if (bus->iommu_ops->default_domain) { + if (ops->default_domain) { if (req_type) return ERR_PTR(-EINVAL); - return bus->iommu_ops->default_domain; + return ops->default_domain; } if (req_type) - return __iommu_group_alloc_default_domain(bus, group, req_type); + return __iommu_group_alloc_default_domain(group, req_type); /* The driver gave no guidance on what type to use, try the default */ - dom = __iommu_group_alloc_default_domain(bus, group, iommu_def_domain_type); + dom = __iommu_group_alloc_default_domain(group, iommu_def_domain_type); if (dom) return dom; /* Otherwise IDENTITY and DMA_FQ defaults will try DMA */ if (iommu_def_domain_type == IOMMU_DOMAIN_DMA) return NULL; - dom = __iommu_group_alloc_default_domain(bus, group, IOMMU_DOMAIN_DMA); + dom = __iommu_group_alloc_default_domain(group, IOMMU_DOMAIN_DMA); if (!dom) return NULL; @@ -2043,19 +2040,16 @@ void iommu_set_fault_handler(struct iommu_domain *domain, } EXPORT_SYMBOL_GPL(iommu_set_fault_handler); -static struct iommu_domain *__iommu_domain_alloc(const struct bus_type *bus, - unsigned type) +static struct iommu_domain *__iommu_domain_alloc(const struct iommu_ops *ops, + unsigned int type) { struct iommu_domain *domain; unsigned int alloc_type = type & IOMMU_DOMAIN_ALLOC_FLAGS; - if (bus == NULL || bus->iommu_ops == NULL) - return NULL; + if (alloc_type == IOMMU_DOMAIN_IDENTITY && ops->identity_domain) + return ops->identity_domain; - if (alloc_type == IOMMU_DOMAIN_IDENTITY && bus->iommu_ops->identity_domain) - return bus->iommu_ops->identity_domain; - - domain = bus->iommu_ops->domain_alloc(alloc_type); + domain = ops->domain_alloc(alloc_type); if (!domain) return NULL; @@ -2065,10 +2059,10 @@ static struct iommu_domain *__iommu_domain_alloc(const struct bus_type *bus, * may override this later */ if (!domain->pgsize_bitmap) - domain->pgsize_bitmap = bus->iommu_ops->pgsize_bitmap; + domain->pgsize_bitmap = ops->pgsize_bitmap; if (!domain->ops) - domain->ops = bus->iommu_ops->default_domain_ops; + domain->ops = ops->default_domain_ops; if (iommu_is_dma_domain(domain) && iommu_get_dma_cookie(domain)) { iommu_domain_free(domain); @@ -2077,9 +2071,17 @@ static struct iommu_domain *__iommu_domain_alloc(const struct bus_type *bus, return domain; } +static struct iommu_domain * +__iommu_group_domain_alloc(struct iommu_group *group, unsigned int type) +{ + return __iommu_domain_alloc(group_iommu_ops(group), type); +} + struct iommu_domain *iommu_domain_alloc(const struct bus_type *bus) { - return __iommu_domain_alloc(bus, IOMMU_DOMAIN_UNMANAGED); + if (bus == NULL || bus->iommu_ops == NULL) + return NULL; + return __iommu_domain_alloc(bus->iommu_ops, IOMMU_DOMAIN_UNMANAGED); } EXPORT_SYMBOL_GPL(iommu_domain_alloc); @@ -3239,21 +3241,18 @@ void iommu_device_unuse_default_domain(struct device *dev) static int __iommu_group_alloc_blocking_domain(struct iommu_group *group) { - struct group_device *dev = - list_first_entry(&group->devices, struct group_device, list); - if (group->blocking_domain) return 0; group->blocking_domain = - __iommu_domain_alloc(dev->dev->bus, IOMMU_DOMAIN_BLOCKED); + __iommu_group_domain_alloc(group, IOMMU_DOMAIN_BLOCKED); if (!group->blocking_domain) { /* * For drivers that do not yet understand IOMMU_DOMAIN_BLOCKED * create an empty domain instead. */ - group->blocking_domain = __iommu_domain_alloc( - dev->dev->bus, IOMMU_DOMAIN_UNMANAGED); + group->blocking_domain = __iommu_group_domain_alloc( + group, IOMMU_DOMAIN_UNMANAGED); if (!group->blocking_domain) return -EINVAL; } -- GitLab From 4601cd2d7c4c82c4bafc822e1ff630a709eff206 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:55 -0300 Subject: [PATCH 0140/1451] iommu: Add ops->domain_alloc_paging() This callback requests the driver to create only a __IOMMU_DOMAIN_PAGING domain, so it saves a few lines in a lot of drivers needlessly checking the type. More critically, this allows us to sweep out all the IOMMU_DOMAIN_UNMANAGED and IOMMU_DOMAIN_DMA checks from a lot of the drivers, simplifying what is going on in the code and ultimately removing the now-unused special cases in drivers where they did not support IOMMU_DOMAIN_DMA. domain_alloc_paging() should return a struct iommu_domain that is functionally compatible with ARM_DMA_USE_IOMMU, dma-iommu.c and iommufd. Be forwards looking and pass in a 'struct device *' argument. We can provide this when allocating the default_domain. No drivers will look at this. Tested-by: Steven Price Tested-by: Marek Szyprowski Tested-by: Nicolin Chen Reviewed-by: Lu Baolu Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/22-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 17 ++++++++++++++--- include/linux/iommu.h | 3 +++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 38856d542afc3..fe033043be467 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -2041,6 +2041,7 @@ void iommu_set_fault_handler(struct iommu_domain *domain, EXPORT_SYMBOL_GPL(iommu_set_fault_handler); static struct iommu_domain *__iommu_domain_alloc(const struct iommu_ops *ops, + struct device *dev, unsigned int type) { struct iommu_domain *domain; @@ -2048,8 +2049,13 @@ static struct iommu_domain *__iommu_domain_alloc(const struct iommu_ops *ops, if (alloc_type == IOMMU_DOMAIN_IDENTITY && ops->identity_domain) return ops->identity_domain; + else if (type & __IOMMU_DOMAIN_PAGING && ops->domain_alloc_paging) + domain = ops->domain_alloc_paging(dev); + else if (ops->domain_alloc) + domain = ops->domain_alloc(alloc_type); + else + return NULL; - domain = ops->domain_alloc(alloc_type); if (!domain) return NULL; @@ -2074,14 +2080,19 @@ static struct iommu_domain *__iommu_domain_alloc(const struct iommu_ops *ops, static struct iommu_domain * __iommu_group_domain_alloc(struct iommu_group *group, unsigned int type) { - return __iommu_domain_alloc(group_iommu_ops(group), type); + struct device *dev = + list_first_entry(&group->devices, struct group_device, list) + ->dev; + + return __iommu_domain_alloc(group_iommu_ops(group), dev, type); } struct iommu_domain *iommu_domain_alloc(const struct bus_type *bus) { if (bus == NULL || bus->iommu_ops == NULL) return NULL; - return __iommu_domain_alloc(bus->iommu_ops, IOMMU_DOMAIN_UNMANAGED); + return __iommu_domain_alloc(bus->iommu_ops, NULL, + IOMMU_DOMAIN_UNMANAGED); } EXPORT_SYMBOL_GPL(iommu_domain_alloc); diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 511dfeea52721..3f173307434dc 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -239,6 +239,8 @@ struct iommu_iotlb_gather { * use. The information type is one of enum iommu_hw_info_type defined * in include/uapi/linux/iommufd.h. * @domain_alloc: allocate iommu domain + * @domain_alloc_paging: Allocate an iommu_domain that can be used for + * UNMANAGED, DMA, and DMA_FQ domain types. * @probe_device: Add device to iommu driver handling * @release_device: Remove device from iommu driver handling * @probe_finalize: Do final setup work after the device is added to an IOMMU @@ -273,6 +275,7 @@ struct iommu_ops { /* Domain allocation and freeing by the iommu driver */ struct iommu_domain *(*domain_alloc)(unsigned iommu_domain_type); + struct iommu_domain *(*domain_alloc_paging)(struct device *dev); struct iommu_device *(*probe_device)(struct device *dev); void (*release_device)(struct device *dev); -- GitLab From 3529375e7777b0f9b77c53df9a7da122bd165ae7 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:56 -0300 Subject: [PATCH 0141/1451] iommu: Convert simple drivers with DOMAIN_DMA to domain_alloc_paging() These drivers are all trivially converted since the function is only called if the domain type is going to be IOMMU_DOMAIN_UNMANAGED/DMA. Tested-by: Heiko Stuebner Tested-by: Steven Price Tested-by: Marek Szyprowski Tested-by: Nicolin Chen Reviewed-by: Lu Baolu Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Tested-by: Yong Wu #For mtk_iommu.c Link: https://lore.kernel.org/r/23-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/arm/arm-smmu/qcom_iommu.c | 6 ++---- drivers/iommu/exynos-iommu.c | 7 ++----- drivers/iommu/ipmmu-vmsa.c | 7 ++----- drivers/iommu/mtk_iommu.c | 7 ++----- drivers/iommu/rockchip-iommu.c | 7 ++----- drivers/iommu/sprd-iommu.c | 7 ++----- drivers/iommu/sun50i-iommu.c | 9 +++------ drivers/iommu/tegra-smmu.c | 7 ++----- 8 files changed, 17 insertions(+), 40 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c index bc45d18f350cb..97b2122032b23 100644 --- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c +++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c @@ -332,12 +332,10 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain, return ret; } -static struct iommu_domain *qcom_iommu_domain_alloc(unsigned type) +static struct iommu_domain *qcom_iommu_domain_alloc_paging(struct device *dev) { struct qcom_iommu_domain *qcom_domain; - if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA) - return NULL; /* * Allocate the domain and initialise some of its data structures. * We can't really do anything meaningful until we've added a @@ -605,7 +603,7 @@ static int qcom_iommu_of_xlate(struct device *dev, struct of_phandle_args *args) static const struct iommu_ops qcom_iommu_ops = { .identity_domain = &qcom_iommu_identity_domain, .capable = qcom_iommu_capable, - .domain_alloc = qcom_iommu_domain_alloc, + .domain_alloc_paging = qcom_iommu_domain_alloc_paging, .probe_device = qcom_iommu_probe_device, .device_group = generic_device_group, .of_xlate = qcom_iommu_of_xlate, diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 5e12b85dfe870..d6dead2ed10c1 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -887,7 +887,7 @@ static inline void exynos_iommu_set_pte(sysmmu_pte_t *ent, sysmmu_pte_t val) DMA_TO_DEVICE); } -static struct iommu_domain *exynos_iommu_domain_alloc(unsigned type) +static struct iommu_domain *exynos_iommu_domain_alloc_paging(struct device *dev) { struct exynos_iommu_domain *domain; dma_addr_t handle; @@ -896,9 +896,6 @@ static struct iommu_domain *exynos_iommu_domain_alloc(unsigned type) /* Check if correct PTE offsets are initialized */ BUG_ON(PG_ENT_SHIFT < 0 || !dma_dev); - if (type != IOMMU_DOMAIN_DMA && type != IOMMU_DOMAIN_UNMANAGED) - return NULL; - domain = kzalloc(sizeof(*domain), GFP_KERNEL); if (!domain) return NULL; @@ -1472,7 +1469,7 @@ static int exynos_iommu_of_xlate(struct device *dev, static const struct iommu_ops exynos_iommu_ops = { .identity_domain = &exynos_identity_domain, - .domain_alloc = exynos_iommu_domain_alloc, + .domain_alloc_paging = exynos_iommu_domain_alloc_paging, .device_group = generic_device_group, .probe_device = exynos_iommu_probe_device, .release_device = exynos_iommu_release_device, diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index 04830d3931d23..eaabae7615776 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -563,13 +563,10 @@ static irqreturn_t ipmmu_irq(int irq, void *dev) * IOMMU Operations */ -static struct iommu_domain *ipmmu_domain_alloc(unsigned type) +static struct iommu_domain *ipmmu_domain_alloc_paging(struct device *dev) { struct ipmmu_vmsa_domain *domain; - if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA) - return NULL; - domain = kzalloc(sizeof(*domain), GFP_KERNEL); if (!domain) return NULL; @@ -892,7 +889,7 @@ static struct iommu_group *ipmmu_find_group(struct device *dev) static const struct iommu_ops ipmmu_ops = { .identity_domain = &ipmmu_iommu_identity_domain, - .domain_alloc = ipmmu_domain_alloc, + .domain_alloc_paging = ipmmu_domain_alloc_paging, .probe_device = ipmmu_probe_device, .release_device = ipmmu_release_device, .probe_finalize = ipmmu_probe_finalize, diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index 164f9759e1c03..19ef50221c93d 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -689,13 +689,10 @@ static int mtk_iommu_domain_finalise(struct mtk_iommu_domain *dom, return 0; } -static struct iommu_domain *mtk_iommu_domain_alloc(unsigned type) +static struct iommu_domain *mtk_iommu_domain_alloc_paging(struct device *dev) { struct mtk_iommu_domain *dom; - if (type != IOMMU_DOMAIN_DMA && type != IOMMU_DOMAIN_UNMANAGED) - return NULL; - dom = kzalloc(sizeof(*dom), GFP_KERNEL); if (!dom) return NULL; @@ -1019,7 +1016,7 @@ static void mtk_iommu_get_resv_regions(struct device *dev, static const struct iommu_ops mtk_iommu_ops = { .identity_domain = &mtk_iommu_identity_domain, - .domain_alloc = mtk_iommu_domain_alloc, + .domain_alloc_paging = mtk_iommu_domain_alloc_paging, .probe_device = mtk_iommu_probe_device, .release_device = mtk_iommu_release_device, .device_group = mtk_iommu_device_group, diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index a582525d36f8c..5deb64b9cbe4b 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -1043,13 +1043,10 @@ static int rk_iommu_attach_device(struct iommu_domain *domain, return ret; } -static struct iommu_domain *rk_iommu_domain_alloc(unsigned type) +static struct iommu_domain *rk_iommu_domain_alloc_paging(struct device *dev) { struct rk_iommu_domain *rk_domain; - if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA) - return NULL; - if (!dma_dev) return NULL; @@ -1172,7 +1169,7 @@ static int rk_iommu_of_xlate(struct device *dev, static const struct iommu_ops rk_iommu_ops = { .identity_domain = &rk_identity_domain, - .domain_alloc = rk_iommu_domain_alloc, + .domain_alloc_paging = rk_iommu_domain_alloc_paging, .probe_device = rk_iommu_probe_device, .release_device = rk_iommu_release_device, .device_group = rk_iommu_device_group, diff --git a/drivers/iommu/sprd-iommu.c b/drivers/iommu/sprd-iommu.c index 2fa9afebd4f5f..0642f0a3a32ab 100644 --- a/drivers/iommu/sprd-iommu.c +++ b/drivers/iommu/sprd-iommu.c @@ -134,13 +134,10 @@ sprd_iommu_pgt_size(struct iommu_domain *domain) SPRD_IOMMU_PAGE_SHIFT) * sizeof(u32); } -static struct iommu_domain *sprd_iommu_domain_alloc(unsigned int domain_type) +static struct iommu_domain *sprd_iommu_domain_alloc_paging(struct device *dev) { struct sprd_iommu_domain *dom; - if (domain_type != IOMMU_DOMAIN_DMA && domain_type != IOMMU_DOMAIN_UNMANAGED) - return NULL; - dom = kzalloc(sizeof(*dom), GFP_KERNEL); if (!dom) return NULL; @@ -421,7 +418,7 @@ static int sprd_iommu_of_xlate(struct device *dev, struct of_phandle_args *args) static const struct iommu_ops sprd_iommu_ops = { - .domain_alloc = sprd_iommu_domain_alloc, + .domain_alloc_paging = sprd_iommu_domain_alloc_paging, .probe_device = sprd_iommu_probe_device, .device_group = sprd_iommu_device_group, .of_xlate = sprd_iommu_of_xlate, diff --git a/drivers/iommu/sun50i-iommu.c b/drivers/iommu/sun50i-iommu.c index 0bf08b120cf10..d6629b0a9389f 100644 --- a/drivers/iommu/sun50i-iommu.c +++ b/drivers/iommu/sun50i-iommu.c @@ -667,14 +667,11 @@ static phys_addr_t sun50i_iommu_iova_to_phys(struct iommu_domain *domain, sun50i_iova_get_page_offset(iova); } -static struct iommu_domain *sun50i_iommu_domain_alloc(unsigned type) +static struct iommu_domain * +sun50i_iommu_domain_alloc_paging(struct device *dev) { struct sun50i_iommu_domain *sun50i_domain; - if (type != IOMMU_DOMAIN_DMA && - type != IOMMU_DOMAIN_UNMANAGED) - return NULL; - sun50i_domain = kzalloc(sizeof(*sun50i_domain), GFP_KERNEL); if (!sun50i_domain) return NULL; @@ -840,7 +837,7 @@ static const struct iommu_ops sun50i_iommu_ops = { .identity_domain = &sun50i_iommu_identity_domain, .pgsize_bitmap = SZ_4K, .device_group = sun50i_iommu_device_group, - .domain_alloc = sun50i_iommu_domain_alloc, + .domain_alloc_paging = sun50i_iommu_domain_alloc_paging, .of_xlate = sun50i_iommu_of_xlate, .probe_device = sun50i_iommu_probe_device, .default_domain_ops = &(const struct iommu_domain_ops) { diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index b91ad1b5a20d3..1764a63347b04 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -272,13 +272,10 @@ static void tegra_smmu_free_asid(struct tegra_smmu *smmu, unsigned int id) clear_bit(id, smmu->asids); } -static struct iommu_domain *tegra_smmu_domain_alloc(unsigned type) +static struct iommu_domain *tegra_smmu_domain_alloc_paging(struct device *dev) { struct tegra_smmu_as *as; - if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA) - return NULL; - as = kzalloc(sizeof(*as), GFP_KERNEL); if (!as) return NULL; @@ -991,7 +988,7 @@ static int tegra_smmu_def_domain_type(struct device *dev) static const struct iommu_ops tegra_smmu_ops = { .identity_domain = &tegra_smmu_identity_domain, .def_domain_type = &tegra_smmu_def_domain_type, - .domain_alloc = tegra_smmu_domain_alloc, + .domain_alloc_paging = tegra_smmu_domain_alloc_paging, .probe_device = tegra_smmu_probe_device, .device_group = tegra_smmu_device_group, .of_xlate = tegra_smmu_of_xlate, -- GitLab From 4efd98d41ea71835f4d291176ff1fd0a1803dfd5 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 13 Sep 2023 10:43:57 -0300 Subject: [PATCH 0142/1451] iommu: Convert remaining simple drivers to domain_alloc_paging() These drivers don't support IOMMU_DOMAIN_DMA, so this commit effectively allows them to support that mode. The prior work to require default_domains makes this safe because every one of these drivers is either compilation incompatible with dma-iommu.c, or already establishing a default_domain. In both cases alloc_domain() will never be called with IOMMU_DOMAIN_DMA for these drivers so it is safe to drop the test. Removing these tests clarifies that the domain allocation path is only about the functionality of a paging domain and has nothing to do with policy of how the paging domain is used for UNMANAGED/DMA/DMA_FQ. Tested-by: Niklas Schnelle Tested-by: Steven Price Tested-by: Marek Szyprowski Tested-by: Nicolin Chen Reviewed-by: Lu Baolu Reviewed-by: Jerry Snitselaar Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/24-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/msm_iommu.c | 7 ++----- drivers/iommu/mtk_iommu_v1.c | 7 ++----- drivers/iommu/omap-iommu.c | 7 ++----- drivers/iommu/s390-iommu.c | 7 ++----- 4 files changed, 8 insertions(+), 20 deletions(-) diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c index 26ed81cfeee89..a163cee0b7242 100644 --- a/drivers/iommu/msm_iommu.c +++ b/drivers/iommu/msm_iommu.c @@ -302,13 +302,10 @@ static void __program_context(void __iomem *base, int ctx, SET_M(base, ctx, 1); } -static struct iommu_domain *msm_iommu_domain_alloc(unsigned type) +static struct iommu_domain *msm_iommu_domain_alloc_paging(struct device *dev) { struct msm_priv *priv; - if (type != IOMMU_DOMAIN_UNMANAGED) - return NULL; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) goto fail_nomem; @@ -691,7 +688,7 @@ irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id) static struct iommu_ops msm_iommu_ops = { .identity_domain = &msm_iommu_identity_domain, - .domain_alloc = msm_iommu_domain_alloc, + .domain_alloc_paging = msm_iommu_domain_alloc_paging, .probe_device = msm_iommu_probe_device, .device_group = generic_device_group, .pgsize_bitmap = MSM_IOMMU_PGSIZES, diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c index 7c0c1d50df5f7..67e044c1a7d93 100644 --- a/drivers/iommu/mtk_iommu_v1.c +++ b/drivers/iommu/mtk_iommu_v1.c @@ -270,13 +270,10 @@ static int mtk_iommu_v1_domain_finalise(struct mtk_iommu_v1_data *data) return 0; } -static struct iommu_domain *mtk_iommu_v1_domain_alloc(unsigned type) +static struct iommu_domain *mtk_iommu_v1_domain_alloc_paging(struct device *dev) { struct mtk_iommu_v1_domain *dom; - if (type != IOMMU_DOMAIN_UNMANAGED) - return NULL; - dom = kzalloc(sizeof(*dom), GFP_KERNEL); if (!dom) return NULL; @@ -585,7 +582,7 @@ static int mtk_iommu_v1_hw_init(const struct mtk_iommu_v1_data *data) static const struct iommu_ops mtk_iommu_v1_ops = { .identity_domain = &mtk_iommu_v1_identity_domain, - .domain_alloc = mtk_iommu_v1_domain_alloc, + .domain_alloc_paging = mtk_iommu_v1_domain_alloc_paging, .probe_device = mtk_iommu_v1_probe_device, .probe_finalize = mtk_iommu_v1_probe_finalize, .release_device = mtk_iommu_v1_release_device, diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index 34340ef15241b..fcf99bd195b32 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -1580,13 +1580,10 @@ static struct iommu_domain omap_iommu_identity_domain = { .ops = &omap_iommu_identity_ops, }; -static struct iommu_domain *omap_iommu_domain_alloc(unsigned type) +static struct iommu_domain *omap_iommu_domain_alloc_paging(struct device *dev) { struct omap_iommu_domain *omap_domain; - if (type != IOMMU_DOMAIN_UNMANAGED) - return NULL; - omap_domain = kzalloc(sizeof(*omap_domain), GFP_KERNEL); if (!omap_domain) return NULL; @@ -1748,7 +1745,7 @@ static struct iommu_group *omap_iommu_device_group(struct device *dev) static const struct iommu_ops omap_iommu_ops = { .identity_domain = &omap_iommu_identity_domain, - .domain_alloc = omap_iommu_domain_alloc, + .domain_alloc_paging = omap_iommu_domain_alloc_paging, .probe_device = omap_iommu_probe_device, .release_device = omap_iommu_release_device, .device_group = omap_iommu_device_group, diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c index f0c867c57a5b9..5695ad71d60e2 100644 --- a/drivers/iommu/s390-iommu.c +++ b/drivers/iommu/s390-iommu.c @@ -39,13 +39,10 @@ static bool s390_iommu_capable(struct device *dev, enum iommu_cap cap) } } -static struct iommu_domain *s390_domain_alloc(unsigned domain_type) +static struct iommu_domain *s390_domain_alloc_paging(struct device *dev) { struct s390_domain *s390_domain; - if (domain_type != IOMMU_DOMAIN_UNMANAGED) - return NULL; - s390_domain = kzalloc(sizeof(*s390_domain), GFP_KERNEL); if (!s390_domain) return NULL; @@ -447,7 +444,7 @@ void zpci_destroy_iommu(struct zpci_dev *zdev) static const struct iommu_ops s390_iommu_ops = { .default_domain = &s390_iommu_platform_domain, .capable = s390_iommu_capable, - .domain_alloc = s390_domain_alloc, + .domain_alloc_paging = s390_domain_alloc_paging, .probe_device = s390_iommu_probe_device, .release_device = s390_iommu_release_device, .device_group = generic_device_group, -- GitLab From e946f8e3e62bf05da21a14658f8cb05e2a616260 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 22 Aug 2023 13:15:56 -0300 Subject: [PATCH 0143/1451] iommu: Remove useless group refcounting Several functions obtain the group reference and then release it before returning. This gives the impression that the refcount is protecting something for the duration of the function. In truth all of these functions are called in places that know a device driver is probed to the device and our locking rules already require that dev->iommu_group cannot change while a driver is attached to the struct device. If this was not the case then this code is already at risk of triggering UAF as it is racy if the dev->iommu_group is concurrently going to NULL/free. refcount debugging will throw a WARN if kobject_get() is called on a 0 refcount object to highlight the bug. Remove the confusing refcounting and leave behind a comment about the restriction. Reviewed-by: Lu Baolu Reviewed-by: Kevin Tian Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/1-v1-c869a95191f2+5e8-iommu_single_grp_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 57 ++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index fe033043be467..6483d6e19a5ec 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -2152,10 +2152,10 @@ static int __iommu_attach_device(struct iommu_domain *domain, */ int iommu_attach_device(struct iommu_domain *domain, struct device *dev) { - struct iommu_group *group; + /* Caller must be a probed driver on dev */ + struct iommu_group *group = dev->iommu_group; int ret; - group = iommu_group_get(dev); if (!group) return -ENODEV; @@ -2172,8 +2172,6 @@ int iommu_attach_device(struct iommu_domain *domain, struct device *dev) out_unlock: mutex_unlock(&group->mutex); - iommu_group_put(group); - return ret; } EXPORT_SYMBOL_GPL(iommu_attach_device); @@ -2188,9 +2186,9 @@ int iommu_deferred_attach(struct device *dev, struct iommu_domain *domain) void iommu_detach_device(struct iommu_domain *domain, struct device *dev) { - struct iommu_group *group; + /* Caller must be a probed driver on dev */ + struct iommu_group *group = dev->iommu_group; - group = iommu_group_get(dev); if (!group) return; @@ -2202,24 +2200,18 @@ void iommu_detach_device(struct iommu_domain *domain, struct device *dev) out_unlock: mutex_unlock(&group->mutex); - iommu_group_put(group); } EXPORT_SYMBOL_GPL(iommu_detach_device); struct iommu_domain *iommu_get_domain_for_dev(struct device *dev) { - struct iommu_domain *domain; - struct iommu_group *group; + /* Caller must be a probed driver on dev */ + struct iommu_group *group = dev->iommu_group; - group = iommu_group_get(dev); if (!group) return NULL; - domain = group->domain; - - iommu_group_put(group); - - return domain; + return group->domain; } EXPORT_SYMBOL_GPL(iommu_get_domain_for_dev); @@ -3203,7 +3195,8 @@ static bool iommu_is_default_domain(struct iommu_group *group) */ int iommu_device_use_default_domain(struct device *dev) { - struct iommu_group *group = iommu_group_get(dev); + /* Caller is the driver core during the pre-probe path */ + struct iommu_group *group = dev->iommu_group; int ret = 0; if (!group) @@ -3222,8 +3215,6 @@ int iommu_device_use_default_domain(struct device *dev) unlock_out: mutex_unlock(&group->mutex); - iommu_group_put(group); - return ret; } @@ -3237,7 +3228,8 @@ int iommu_device_use_default_domain(struct device *dev) */ void iommu_device_unuse_default_domain(struct device *dev) { - struct iommu_group *group = iommu_group_get(dev); + /* Caller is the driver core during the post-probe path */ + struct iommu_group *group = dev->iommu_group; if (!group) return; @@ -3247,7 +3239,6 @@ void iommu_device_unuse_default_domain(struct device *dev) group->owner_cnt--; mutex_unlock(&group->mutex); - iommu_group_put(group); } static int __iommu_group_alloc_blocking_domain(struct iommu_group *group) @@ -3331,13 +3322,13 @@ EXPORT_SYMBOL_GPL(iommu_group_claim_dma_owner); */ int iommu_device_claim_dma_owner(struct device *dev, void *owner) { - struct iommu_group *group; + /* Caller must be a probed driver on dev */ + struct iommu_group *group = dev->iommu_group; int ret = 0; if (WARN_ON(!owner)) return -EINVAL; - group = iommu_group_get(dev); if (!group) return -ENODEV; @@ -3354,8 +3345,6 @@ int iommu_device_claim_dma_owner(struct device *dev, void *owner) ret = __iommu_take_dma_ownership(group, owner); unlock_out: mutex_unlock(&group->mutex); - iommu_group_put(group); - return ret; } EXPORT_SYMBOL_GPL(iommu_device_claim_dma_owner); @@ -3393,7 +3382,8 @@ EXPORT_SYMBOL_GPL(iommu_group_release_dma_owner); */ void iommu_device_release_dma_owner(struct device *dev) { - struct iommu_group *group = iommu_group_get(dev); + /* Caller must be a probed driver on dev */ + struct iommu_group *group = dev->iommu_group; mutex_lock(&group->mutex); if (group->owner_cnt > 1) @@ -3401,7 +3391,6 @@ void iommu_device_release_dma_owner(struct device *dev) else __iommu_release_dma_ownership(group); mutex_unlock(&group->mutex); - iommu_group_put(group); } EXPORT_SYMBOL_GPL(iommu_device_release_dma_owner); @@ -3462,14 +3451,14 @@ static void __iommu_remove_group_pasid(struct iommu_group *group, int iommu_attach_device_pasid(struct iommu_domain *domain, struct device *dev, ioasid_t pasid) { - struct iommu_group *group; + /* Caller must be a probed driver on dev */ + struct iommu_group *group = dev->iommu_group; void *curr; int ret; if (!domain->ops->set_dev_pasid) return -EOPNOTSUPP; - group = iommu_group_get(dev); if (!group) return -ENODEV; @@ -3487,8 +3476,6 @@ int iommu_attach_device_pasid(struct iommu_domain *domain, } out_unlock: mutex_unlock(&group->mutex); - iommu_group_put(group); - return ret; } EXPORT_SYMBOL_GPL(iommu_attach_device_pasid); @@ -3505,14 +3492,13 @@ EXPORT_SYMBOL_GPL(iommu_attach_device_pasid); void iommu_detach_device_pasid(struct iommu_domain *domain, struct device *dev, ioasid_t pasid) { - struct iommu_group *group = iommu_group_get(dev); + /* Caller must be a probed driver on dev */ + struct iommu_group *group = dev->iommu_group; mutex_lock(&group->mutex); __iommu_remove_group_pasid(group, pasid); WARN_ON(xa_erase(&group->pasid_array, pasid) != domain); mutex_unlock(&group->mutex); - - iommu_group_put(group); } EXPORT_SYMBOL_GPL(iommu_detach_device_pasid); @@ -3534,10 +3520,10 @@ struct iommu_domain *iommu_get_domain_for_dev_pasid(struct device *dev, ioasid_t pasid, unsigned int type) { + /* Caller must be a probed driver on dev */ + struct iommu_group *group = dev->iommu_group; struct iommu_domain *domain; - struct iommu_group *group; - group = iommu_group_get(dev); if (!group) return NULL; @@ -3546,7 +3532,6 @@ struct iommu_domain *iommu_get_domain_for_dev_pasid(struct device *dev, if (type && domain && domain->type != type) domain = ERR_PTR(-EBUSY); xa_unlock(&group->pasid_array); - iommu_group_put(group); return domain; } -- GitLab From e8f52d84cf0b6d1862ab62f7ed705f78690d11b2 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 22 Aug 2023 13:15:57 -0300 Subject: [PATCH 0144/1451] iommu: Add generic_single_device_group() This implements the common pattern seen in drivers of a single iommu_group for the entire iommu driver instance. Implement this in core code so the drivers that want this can select it from their ops. Reviewed-by: Lu Baolu Reviewed-by: Kevin Tian Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/2-v1-c869a95191f2+5e8-iommu_single_grp_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 28 +++++++++++++++++++++++++++- include/linux/iommu.h | 3 +++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 6483d6e19a5ec..03202314322bd 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -292,6 +292,10 @@ void iommu_device_unregister(struct iommu_device *iommu) spin_lock(&iommu_device_lock); list_del(&iommu->list); spin_unlock(&iommu_device_lock); + + /* Pairs with the alloc in generic_single_device_group() */ + iommu_group_put(iommu->singleton_group); + iommu->singleton_group = NULL; } EXPORT_SYMBOL_GPL(iommu_device_unregister); @@ -406,6 +410,7 @@ static int iommu_init_device(struct device *dev, const struct iommu_ops *ops) ret = PTR_ERR(iommu_dev); goto err_module_put; } + dev->iommu->iommu_dev = iommu_dev; ret = iommu_device_link(iommu_dev, dev); if (ret) @@ -420,7 +425,6 @@ static int iommu_init_device(struct device *dev, const struct iommu_ops *ops) } dev->iommu_group = group; - dev->iommu->iommu_dev = iommu_dev; dev->iommu->max_pasids = dev_iommu_get_max_pasids(dev); if (ops->is_attach_deferred) dev->iommu->attach_deferred = ops->is_attach_deferred(dev); @@ -434,6 +438,7 @@ static int iommu_init_device(struct device *dev, const struct iommu_ops *ops) err_module_put: module_put(ops->owner); err_free: + dev->iommu->iommu_dev = NULL; dev_iommu_free(dev); return ret; } @@ -1637,6 +1642,27 @@ struct iommu_group *generic_device_group(struct device *dev) } EXPORT_SYMBOL_GPL(generic_device_group); +/* + * Generic device_group call-back function. It just allocates one + * iommu-group per iommu driver instance shared by every device + * probed by that iommu driver. + */ +struct iommu_group *generic_single_device_group(struct device *dev) +{ + struct iommu_device *iommu = dev->iommu->iommu_dev; + + if (!iommu->singleton_group) { + struct iommu_group *group; + + group = iommu_group_alloc(); + if (IS_ERR(group)) + return group; + iommu->singleton_group = group; + } + return iommu_group_ref_get(iommu->singleton_group); +} +EXPORT_SYMBOL_GPL(generic_single_device_group); + /* * Use standard PCI bus topology, isolation features, and DMA alias quirks * to find or create an IOMMU group for a device. diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 3f173307434dc..5b693be3d35fc 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -378,6 +378,7 @@ struct iommu_domain_ops { * @list: Used by the iommu-core to keep a list of registered iommus * @ops: iommu-ops for talking to this iommu * @dev: struct device for sysfs handling + * @singleton_group: Used internally for drivers that have only one group * @max_pasids: number of supported PASIDs */ struct iommu_device { @@ -385,6 +386,7 @@ struct iommu_device { const struct iommu_ops *ops; struct fwnode_handle *fwnode; struct device *dev; + struct iommu_group *singleton_group; u32 max_pasids; }; @@ -648,6 +650,7 @@ extern struct iommu_group *pci_device_group(struct device *dev); extern struct iommu_group *generic_device_group(struct device *dev); /* FSL-MC device grouping function */ struct iommu_group *fsl_mc_device_group(struct device *dev); +extern struct iommu_group *generic_single_device_group(struct device *dev); /** * struct iommu_fwspec - per-device IOMMU instance data -- GitLab From 4f43b6b6d1e025ecac792298d67a7c6c11334cfc Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 22 Aug 2023 13:15:58 -0300 Subject: [PATCH 0145/1451] iommu/sun50i: Convert to generic_single_device_group() Use the new helper. Signed-off-by: Jason Gunthorpe Acked-by: Jernej Skrabec Link: https://lore.kernel.org/r/3-v1-c869a95191f2+5e8-iommu_single_grp_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/sun50i-iommu.c | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/drivers/iommu/sun50i-iommu.c b/drivers/iommu/sun50i-iommu.c index d6629b0a9389f..000aa22680993 100644 --- a/drivers/iommu/sun50i-iommu.c +++ b/drivers/iommu/sun50i-iommu.c @@ -107,7 +107,6 @@ struct sun50i_iommu { struct clk *clk; struct iommu_domain *domain; - struct iommu_group *group; struct kmem_cache *pt_pool; }; @@ -815,13 +814,6 @@ static struct iommu_device *sun50i_iommu_probe_device(struct device *dev) return &iommu->iommu; } -static struct iommu_group *sun50i_iommu_device_group(struct device *dev) -{ - struct sun50i_iommu *iommu = sun50i_iommu_from_dev(dev); - - return iommu_group_ref_get(iommu->group); -} - static int sun50i_iommu_of_xlate(struct device *dev, struct of_phandle_args *args) { @@ -836,7 +828,7 @@ static int sun50i_iommu_of_xlate(struct device *dev, static const struct iommu_ops sun50i_iommu_ops = { .identity_domain = &sun50i_iommu_identity_domain, .pgsize_bitmap = SZ_4K, - .device_group = sun50i_iommu_device_group, + .device_group = generic_single_device_group, .domain_alloc_paging = sun50i_iommu_domain_alloc_paging, .of_xlate = sun50i_iommu_of_xlate, .probe_device = sun50i_iommu_probe_device, @@ -1004,42 +996,36 @@ static int sun50i_iommu_probe(struct platform_device *pdev) if (!iommu->pt_pool) return -ENOMEM; - iommu->group = iommu_group_alloc(); - if (IS_ERR(iommu->group)) { - ret = PTR_ERR(iommu->group); - goto err_free_cache; - } - iommu->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(iommu->base)) { ret = PTR_ERR(iommu->base); - goto err_free_group; + goto err_free_cache; } irq = platform_get_irq(pdev, 0); if (irq < 0) { ret = irq; - goto err_free_group; + goto err_free_cache; } iommu->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(iommu->clk)) { dev_err(&pdev->dev, "Couldn't get our clock.\n"); ret = PTR_ERR(iommu->clk); - goto err_free_group; + goto err_free_cache; } iommu->reset = devm_reset_control_get(&pdev->dev, NULL); if (IS_ERR(iommu->reset)) { dev_err(&pdev->dev, "Couldn't get our reset line.\n"); ret = PTR_ERR(iommu->reset); - goto err_free_group; + goto err_free_cache; } ret = iommu_device_sysfs_add(&iommu->iommu, &pdev->dev, NULL, dev_name(&pdev->dev)); if (ret) - goto err_free_group; + goto err_free_cache; ret = iommu_device_register(&iommu->iommu, &sun50i_iommu_ops, &pdev->dev); if (ret) @@ -1058,9 +1044,6 @@ static int sun50i_iommu_probe(struct platform_device *pdev) err_remove_sysfs: iommu_device_sysfs_remove(&iommu->iommu); -err_free_group: - iommu_group_put(iommu->group); - err_free_cache: kmem_cache_destroy(iommu->pt_pool); -- GitLab From a62cafe124b3b91ce85d17c036552b59c1243011 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 22 Aug 2023 13:15:59 -0300 Subject: [PATCH 0146/1451] iommu/sprd: Convert to generic_single_device_group() Use the new helper. Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/4-v1-c869a95191f2+5e8-iommu_single_grp_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/sprd-iommu.c | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/drivers/iommu/sprd-iommu.c b/drivers/iommu/sprd-iommu.c index 0642f0a3a32ab..9c33ea6903f6c 100644 --- a/drivers/iommu/sprd-iommu.c +++ b/drivers/iommu/sprd-iommu.c @@ -70,7 +70,6 @@ struct sprd_iommu_device { void __iomem *base; struct device *dev; struct iommu_device iommu; - struct iommu_group *group; struct clk *eb; }; @@ -396,13 +395,6 @@ static struct iommu_device *sprd_iommu_probe_device(struct device *dev) return &sdev->iommu; } -static struct iommu_group *sprd_iommu_device_group(struct device *dev) -{ - struct sprd_iommu_device *sdev = dev_iommu_priv_get(dev); - - return iommu_group_ref_get(sdev->group); -} - static int sprd_iommu_of_xlate(struct device *dev, struct of_phandle_args *args) { struct platform_device *pdev; @@ -420,7 +412,7 @@ static int sprd_iommu_of_xlate(struct device *dev, struct of_phandle_args *args) static const struct iommu_ops sprd_iommu_ops = { .domain_alloc_paging = sprd_iommu_domain_alloc_paging, .probe_device = sprd_iommu_probe_device, - .device_group = sprd_iommu_device_group, + .device_group = generic_single_device_group, .of_xlate = sprd_iommu_of_xlate, .pgsize_bitmap = SPRD_IOMMU_PAGE_SIZE, .owner = THIS_MODULE, @@ -493,16 +485,9 @@ static int sprd_iommu_probe(struct platform_device *pdev) platform_set_drvdata(pdev, sdev); sdev->dev = dev; - /* All the client devices are in the same iommu-group */ - sdev->group = iommu_group_alloc(); - if (IS_ERR(sdev->group)) { - ret = PTR_ERR(sdev->group); - goto free_page; - } - ret = iommu_device_sysfs_add(&sdev->iommu, dev, NULL, dev_name(dev)); if (ret) - goto put_group; + goto free_page; ret = iommu_device_register(&sdev->iommu, &sprd_iommu_ops, dev); if (ret) @@ -527,8 +512,6 @@ static int sprd_iommu_probe(struct platform_device *pdev) iommu_device_unregister(&sdev->iommu); remove_sysfs: iommu_device_sysfs_remove(&sdev->iommu); -put_group: - iommu_group_put(sdev->group); free_page: dma_free_coherent(sdev->dev, SPRD_IOMMU_PAGE_SIZE, sdev->prot_page_va, sdev->prot_page_pa); return ret; @@ -540,9 +523,6 @@ static void sprd_iommu_remove(struct platform_device *pdev) dma_free_coherent(sdev->dev, SPRD_IOMMU_PAGE_SIZE, sdev->prot_page_va, sdev->prot_page_pa); - iommu_group_put(sdev->group); - sdev->group = NULL; - platform_set_drvdata(pdev, NULL); iommu_device_sysfs_remove(&sdev->iommu); iommu_device_unregister(&sdev->iommu); -- GitLab From ef0f48c6be822ead31465d17a429174d56300cf8 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 22 Aug 2023 13:16:00 -0300 Subject: [PATCH 0147/1451] iommu/rockchip: Convert to generic_single_device_group() Use the new helper. Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/5-v1-c869a95191f2+5e8-iommu_single_grp_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/rockchip-iommu.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index 5deb64b9cbe4b..ce8487230209f 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -113,7 +113,6 @@ struct rk_iommu { struct iommu_device iommu; struct list_head node; /* entry in rk_iommu_domain.iommus */ struct iommu_domain *domain; /* domain to which iommu is attached */ - struct iommu_group *group; }; struct rk_iommudata { @@ -1137,15 +1136,6 @@ static void rk_iommu_release_device(struct device *dev) device_link_del(data->link); } -static struct iommu_group *rk_iommu_device_group(struct device *dev) -{ - struct rk_iommu *iommu; - - iommu = rk_iommu_from_dev(dev); - - return iommu_group_ref_get(iommu->group); -} - static int rk_iommu_of_xlate(struct device *dev, struct of_phandle_args *args) { @@ -1172,7 +1162,7 @@ static const struct iommu_ops rk_iommu_ops = { .domain_alloc_paging = rk_iommu_domain_alloc_paging, .probe_device = rk_iommu_probe_device, .release_device = rk_iommu_release_device, - .device_group = rk_iommu_device_group, + .device_group = generic_single_device_group, .pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP, .of_xlate = rk_iommu_of_xlate, .default_domain_ops = &(const struct iommu_domain_ops) { @@ -1260,15 +1250,9 @@ static int rk_iommu_probe(struct platform_device *pdev) if (err) return err; - iommu->group = iommu_group_alloc(); - if (IS_ERR(iommu->group)) { - err = PTR_ERR(iommu->group); - goto err_unprepare_clocks; - } - err = iommu_device_sysfs_add(&iommu->iommu, dev, NULL, dev_name(dev)); if (err) - goto err_put_group; + goto err_unprepare_clocks; err = iommu_device_register(&iommu->iommu, &rk_iommu_ops, dev); if (err) @@ -1305,8 +1289,6 @@ static int rk_iommu_probe(struct platform_device *pdev) pm_runtime_disable(dev); err_remove_sysfs: iommu_device_sysfs_remove(&iommu->iommu); -err_put_group: - iommu_group_put(iommu->group); err_unprepare_clocks: clk_bulk_unprepare(iommu->num_clocks, iommu->clocks); return err; -- GitLab From 8f68911efc16feba1faf073ebea53f6a5b363e7c Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 22 Aug 2023 13:16:01 -0300 Subject: [PATCH 0148/1451] iommu/ipmmu-vmsa: Convert to generic_single_device_group() Use the new helper. This driver is kind of weird since in ARM mode it pretends it has per-device groups, but ARM64 mode does not. Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/6-v1-c869a95191f2+5e8-iommu_single_grp_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/ipmmu-vmsa.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index eaabae7615776..ace1fc4bd34b0 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -64,7 +64,6 @@ struct ipmmu_vmsa_device { struct ipmmu_vmsa_domain *domains[IPMMU_CTX_MAX]; s8 utlb_ctx[IPMMU_UTLB_MAX]; - struct iommu_group *group; struct dma_iommu_mapping *mapping; }; @@ -872,29 +871,18 @@ static void ipmmu_release_device(struct device *dev) arm_iommu_release_mapping(mmu->mapping); } -static struct iommu_group *ipmmu_find_group(struct device *dev) -{ - struct ipmmu_vmsa_device *mmu = to_ipmmu(dev); - struct iommu_group *group; - - if (mmu->group) - return iommu_group_ref_get(mmu->group); - - group = iommu_group_alloc(); - if (!IS_ERR(group)) - mmu->group = group; - - return group; -} - static const struct iommu_ops ipmmu_ops = { .identity_domain = &ipmmu_iommu_identity_domain, .domain_alloc_paging = ipmmu_domain_alloc_paging, .probe_device = ipmmu_probe_device, .release_device = ipmmu_release_device, .probe_finalize = ipmmu_probe_finalize, + /* + * FIXME: The device grouping is a fixed property of the hardware's + * ability to isolate and control DMA, it should not depend on kconfig. + */ .device_group = IS_ENABLED(CONFIG_ARM) && !IS_ENABLED(CONFIG_IOMMU_DMA) - ? generic_device_group : ipmmu_find_group, + ? generic_device_group : generic_single_device_group, .pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K, .of_xlate = ipmmu_of_xlate, .default_domain_ops = &(const struct iommu_domain_ops) { -- GitLab From ebfdc4569eabeacd5ef52364ac0496981652c055 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 22 Aug 2023 13:16:02 -0300 Subject: [PATCH 0149/1451] iommu/omap: Convert to generic_single_device_group() Use the new helper. For some reason omap will probe its driver even if it doesn't load an iommu driver. Keep this working by keeping a bool to track if the iommu driver was started. Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/7-v1-c869a95191f2+5e8-iommu_single_grp_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/omap-iommu.c | 30 ++++-------------------------- drivers/iommu/omap-iommu.h | 2 +- 2 files changed, 5 insertions(+), 27 deletions(-) diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index fcf99bd195b32..0f7d226f55731 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -1225,18 +1225,15 @@ static int omap_iommu_probe(struct platform_device *pdev) platform_set_drvdata(pdev, obj); if (omap_iommu_can_register(pdev)) { - obj->group = iommu_group_alloc(); - if (IS_ERR(obj->group)) - return PTR_ERR(obj->group); - err = iommu_device_sysfs_add(&obj->iommu, obj->dev, NULL, obj->name); if (err) - goto out_group; + return err; err = iommu_device_register(&obj->iommu, &omap_iommu_ops, &pdev->dev); if (err) goto out_sysfs; + obj->has_iommu_driver = true; } pm_runtime_enable(obj->dev); @@ -1252,8 +1249,6 @@ static int omap_iommu_probe(struct platform_device *pdev) out_sysfs: iommu_device_sysfs_remove(&obj->iommu); -out_group: - iommu_group_put(obj->group); return err; } @@ -1261,10 +1256,7 @@ static void omap_iommu_remove(struct platform_device *pdev) { struct omap_iommu *obj = platform_get_drvdata(pdev); - if (obj->group) { - iommu_group_put(obj->group); - obj->group = NULL; - + if (obj->has_iommu_driver) { iommu_device_sysfs_remove(&obj->iommu); iommu_device_unregister(&obj->iommu); } @@ -1729,26 +1721,12 @@ static void omap_iommu_release_device(struct device *dev) } -static struct iommu_group *omap_iommu_device_group(struct device *dev) -{ - struct omap_iommu_arch_data *arch_data = dev_iommu_priv_get(dev); - struct iommu_group *group = ERR_PTR(-EINVAL); - - if (!arch_data) - return ERR_PTR(-ENODEV); - - if (arch_data->iommu_dev) - group = iommu_group_ref_get(arch_data->iommu_dev->group); - - return group; -} - static const struct iommu_ops omap_iommu_ops = { .identity_domain = &omap_iommu_identity_domain, .domain_alloc_paging = omap_iommu_domain_alloc_paging, .probe_device = omap_iommu_probe_device, .release_device = omap_iommu_release_device, - .device_group = omap_iommu_device_group, + .device_group = generic_single_device_group, .pgsize_bitmap = OMAP_IOMMU_PGSIZES, .default_domain_ops = &(const struct iommu_domain_ops) { .attach_dev = omap_iommu_attach_dev, diff --git a/drivers/iommu/omap-iommu.h b/drivers/iommu/omap-iommu.h index 18ee713ede784..27697109ec79a 100644 --- a/drivers/iommu/omap-iommu.h +++ b/drivers/iommu/omap-iommu.h @@ -80,7 +80,7 @@ struct omap_iommu { u32 id; struct iommu_device iommu; - struct iommu_group *group; + bool has_iommu_driver; u8 pwrst; }; -- GitLab From 983efefa44a3eadbc59d9801c61009ee86b7d4f8 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Tue, 12 Sep 2023 17:18:37 +0100 Subject: [PATCH 0150/1451] iommu/exynos: Update to {map,unmap}_pages Trivially update map/unmap to the new interface, which is quite happy for drivers to still process just one page per call. Signed-off-by: Robin Murphy Link: https://lore.kernel.org/r/579176033e92d49ec9fc9f3d33d7b9d4c474f0b4.1694525662.git.robin.murphy@arm.com Signed-off-by: Joerg Roedel --- drivers/iommu/exynos-iommu.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index d6dead2ed10c1..2c6e9094f1e97 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -1229,7 +1229,7 @@ static int lv2set_page(sysmmu_pte_t *pent, phys_addr_t paddr, size_t size, */ static int exynos_iommu_map(struct iommu_domain *iommu_domain, unsigned long l_iova, phys_addr_t paddr, size_t size, - int prot, gfp_t gfp) + size_t count, int prot, gfp_t gfp, size_t *mapped) { struct exynos_iommu_domain *domain = to_exynos_domain(iommu_domain); sysmmu_pte_t *entry; @@ -1263,6 +1263,8 @@ static int exynos_iommu_map(struct iommu_domain *iommu_domain, if (ret) pr_err("%s: Failed(%d) to map %#zx bytes @ %#x\n", __func__, ret, size, iova); + else + *mapped = size; spin_unlock_irqrestore(&domain->pgtablelock, flags); @@ -1284,7 +1286,7 @@ static void exynos_iommu_tlb_invalidate_entry(struct exynos_iommu_domain *domain } static size_t exynos_iommu_unmap(struct iommu_domain *iommu_domain, - unsigned long l_iova, size_t size, + unsigned long l_iova, size_t size, size_t count, struct iommu_iotlb_gather *gather) { struct exynos_iommu_domain *domain = to_exynos_domain(iommu_domain); @@ -1477,8 +1479,8 @@ static const struct iommu_ops exynos_iommu_ops = { .of_xlate = exynos_iommu_of_xlate, .default_domain_ops = &(const struct iommu_domain_ops) { .attach_dev = exynos_iommu_attach_device, - .map = exynos_iommu_map, - .unmap = exynos_iommu_unmap, + .map_pages = exynos_iommu_map, + .unmap_pages = exynos_iommu_unmap, .iova_to_phys = exynos_iommu_iova_to_phys, .free = exynos_iommu_domain_free, } -- GitLab From dc9ffd8dba8b2769528bf60b0fb6551cd02365b7 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Tue, 12 Sep 2023 17:18:38 +0100 Subject: [PATCH 0151/1451] iommu/omap: Update to {map,unmap}_pages Trivially update map/unmap to the new interface, which is quite happy for drivers to still process just one page per call. Signed-off-by: Robin Murphy Link: https://lore.kernel.org/r/7bad94ffccd4cba32bded72e0860974012881e24.1694525662.git.robin.murphy@arm.com Signed-off-by: Joerg Roedel --- drivers/iommu/omap-iommu.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index 0f7d226f55731..c66b070841dd4 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -1310,7 +1310,8 @@ static u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa, int pgsz) } static int omap_iommu_map(struct iommu_domain *domain, unsigned long da, - phys_addr_t pa, size_t bytes, int prot, gfp_t gfp) + phys_addr_t pa, size_t bytes, size_t count, + int prot, gfp_t gfp, size_t *mapped) { struct omap_iommu_domain *omap_domain = to_omap_domain(domain); struct device *dev = omap_domain->dev; @@ -1348,13 +1349,15 @@ static int omap_iommu_map(struct iommu_domain *domain, unsigned long da, oiommu = iommu->iommu_dev; iopgtable_clear_entry(oiommu, da); } + } else { + *mapped = bytes; } return ret; } static size_t omap_iommu_unmap(struct iommu_domain *domain, unsigned long da, - size_t size, struct iommu_iotlb_gather *gather) + size_t size, size_t count, struct iommu_iotlb_gather *gather) { struct omap_iommu_domain *omap_domain = to_omap_domain(domain); struct device *dev = omap_domain->dev; @@ -1730,8 +1733,8 @@ static const struct iommu_ops omap_iommu_ops = { .pgsize_bitmap = OMAP_IOMMU_PGSIZES, .default_domain_ops = &(const struct iommu_domain_ops) { .attach_dev = omap_iommu_attach_dev, - .map = omap_iommu_map, - .unmap = omap_iommu_unmap, + .map_pages = omap_iommu_map, + .unmap_pages = omap_iommu_unmap, .iova_to_phys = omap_iommu_iova_to_phys, .free = omap_iommu_domain_free, } -- GitLab From d47b9777e7bf842f4206d6883c608a103fccd419 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Tue, 12 Sep 2023 17:18:39 +0100 Subject: [PATCH 0152/1451] iommu/rockchip: Update to {map,unmap}_pages Trivially update map/unmap to the new interface, which is quite happy for drivers to still process just one page per call. Signed-off-by: Robin Murphy Link: https://lore.kernel.org/r/ccc21bf7d1d0da8989d4d517a13d0846d6b71a38.1694525662.git.robin.murphy@arm.com Signed-off-by: Joerg Roedel --- drivers/iommu/rockchip-iommu.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index ce8487230209f..2685861c0a126 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -816,7 +816,8 @@ static int rk_iommu_map_iova(struct rk_iommu_domain *rk_domain, u32 *pte_addr, } static int rk_iommu_map(struct iommu_domain *domain, unsigned long _iova, - phys_addr_t paddr, size_t size, int prot, gfp_t gfp) + phys_addr_t paddr, size_t size, size_t count, + int prot, gfp_t gfp, size_t *mapped) { struct rk_iommu_domain *rk_domain = to_rk_domain(domain); unsigned long flags; @@ -849,12 +850,14 @@ static int rk_iommu_map(struct iommu_domain *domain, unsigned long _iova, paddr, size, prot); spin_unlock_irqrestore(&rk_domain->dt_lock, flags); + if (!ret) + *mapped = size; return ret; } static size_t rk_iommu_unmap(struct iommu_domain *domain, unsigned long _iova, - size_t size, struct iommu_iotlb_gather *gather) + size_t size, size_t count, struct iommu_iotlb_gather *gather) { struct rk_iommu_domain *rk_domain = to_rk_domain(domain); unsigned long flags; @@ -1167,8 +1170,8 @@ static const struct iommu_ops rk_iommu_ops = { .of_xlate = rk_iommu_of_xlate, .default_domain_ops = &(const struct iommu_domain_ops) { .attach_dev = rk_iommu_attach_device, - .map = rk_iommu_map, - .unmap = rk_iommu_unmap, + .map_pages = rk_iommu_map, + .unmap_pages = rk_iommu_unmap, .iova_to_phys = rk_iommu_iova_to_phys, .free = rk_iommu_domain_free, } -- GitLab From 8c63d1e3d3a04d99684ad6f6af7f4bb641fd6928 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Tue, 12 Sep 2023 17:18:40 +0100 Subject: [PATCH 0153/1451] iommu/sun50i: Update to {map,unmap}_pages Trivially update map/unmap to the new interface, which is quite happy for drivers to still process just one page per call. Signed-off-by: Robin Murphy Link: https://lore.kernel.org/r/395995e5097803f9a65f2fb79e0732d41c2b8a84.1694525662.git.robin.murphy@arm.com Signed-off-by: Joerg Roedel --- drivers/iommu/sun50i-iommu.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/sun50i-iommu.c b/drivers/iommu/sun50i-iommu.c index 000aa22680993..3c834854eda13 100644 --- a/drivers/iommu/sun50i-iommu.c +++ b/drivers/iommu/sun50i-iommu.c @@ -588,7 +588,8 @@ static u32 *sun50i_dte_get_page_table(struct sun50i_iommu_domain *sun50i_domain, } static int sun50i_iommu_map(struct iommu_domain *domain, unsigned long iova, - phys_addr_t paddr, size_t size, int prot, gfp_t gfp) + phys_addr_t paddr, size_t size, size_t count, + int prot, gfp_t gfp, size_t *mapped) { struct sun50i_iommu_domain *sun50i_domain = to_sun50i_domain(domain); struct sun50i_iommu *iommu = sun50i_domain->iommu; @@ -615,13 +616,14 @@ static int sun50i_iommu_map(struct iommu_domain *domain, unsigned long iova, *pte_addr = sun50i_mk_pte(paddr, prot); sun50i_table_flush(sun50i_domain, pte_addr, 1); + *mapped = size; out: return ret; } static size_t sun50i_iommu_unmap(struct iommu_domain *domain, unsigned long iova, - size_t size, struct iommu_iotlb_gather *gather) + size_t size, size_t count, struct iommu_iotlb_gather *gather) { struct sun50i_iommu_domain *sun50i_domain = to_sun50i_domain(domain); phys_addr_t pt_phys; @@ -838,8 +840,8 @@ static const struct iommu_ops sun50i_iommu_ops = { .iotlb_sync_map = sun50i_iommu_iotlb_sync_map, .iotlb_sync = sun50i_iommu_iotlb_sync, .iova_to_phys = sun50i_iommu_iova_to_phys, - .map = sun50i_iommu_map, - .unmap = sun50i_iommu_unmap, + .map_pages = sun50i_iommu_map, + .unmap_pages = sun50i_iommu_unmap, .free = sun50i_iommu_domain_free, } }; -- GitLab From 39f823dfb59e8a4f718a16e8a1cdac32d42804ad Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Tue, 12 Sep 2023 17:18:42 +0100 Subject: [PATCH 0154/1451] iommu/tegra-smmu: Update to {map,unmap}_pages Trivially update map/unmap to the new interface, which is quite happy for drivers to still process just one page per call. Signed-off-by: Robin Murphy Link: https://lore.kernel.org/r/338c520ed947d6d5b9d0509ccb4588908bd9ce1e.1694525662.git.robin.murphy@arm.com Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-smmu.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 1764a63347b04..d3cb966abfc39 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -764,7 +764,8 @@ __tegra_smmu_unmap(struct iommu_domain *domain, unsigned long iova, } static int tegra_smmu_map(struct iommu_domain *domain, unsigned long iova, - phys_addr_t paddr, size_t size, int prot, gfp_t gfp) + phys_addr_t paddr, size_t size, size_t count, + int prot, gfp_t gfp, size_t *mapped) { struct tegra_smmu_as *as = to_smmu_as(domain); unsigned long flags; @@ -774,11 +775,14 @@ static int tegra_smmu_map(struct iommu_domain *domain, unsigned long iova, ret = __tegra_smmu_map(domain, iova, paddr, size, prot, gfp, &flags); spin_unlock_irqrestore(&as->lock, flags); + if (!ret) + *mapped = size; + return ret; } static size_t tegra_smmu_unmap(struct iommu_domain *domain, unsigned long iova, - size_t size, struct iommu_iotlb_gather *gather) + size_t size, size_t count, struct iommu_iotlb_gather *gather) { struct tegra_smmu_as *as = to_smmu_as(domain); unsigned long flags; @@ -995,8 +999,8 @@ static const struct iommu_ops tegra_smmu_ops = { .pgsize_bitmap = SZ_4K, .default_domain_ops = &(const struct iommu_domain_ops) { .attach_dev = tegra_smmu_attach_dev, - .map = tegra_smmu_map, - .unmap = tegra_smmu_unmap, + .map_pages = tegra_smmu_map, + .unmap_pages = tegra_smmu_unmap, .iova_to_phys = tegra_smmu_iova_to_phys, .free = tegra_smmu_domain_free, } -- GitLab From bd111e987e762d82dc738232c6ed4b3c9bcc5c91 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Tue, 12 Sep 2023 17:18:43 +0100 Subject: [PATCH 0155/1451] iommu: Retire map/unmap ops With everyone now implementing the new interfaces, clean up the last remnants of the old map/unmap ops and simplify the calling logic again. Signed-off-by: Robin Murphy Reviewed-by: Jason Gunthorpe Link: https://lore.kernel.org/r/d2afdf13b2fbf537713c3ec642dfd49d16dd9e6a.1694525662.git.robin.murphy@arm.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 60 ++++++++++--------------------------------- include/linux/iommu.h | 6 ----- 2 files changed, 13 insertions(+), 53 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 03202314322bd..865fa4f179a8f 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -2509,30 +2509,6 @@ static size_t iommu_pgsize(struct iommu_domain *domain, unsigned long iova, return pgsize; } -static int __iommu_map_pages(struct iommu_domain *domain, unsigned long iova, - phys_addr_t paddr, size_t size, int prot, - gfp_t gfp, size_t *mapped) -{ - const struct iommu_domain_ops *ops = domain->ops; - size_t pgsize, count; - int ret; - - pgsize = iommu_pgsize(domain, iova, paddr, size, &count); - - pr_debug("mapping: iova 0x%lx pa %pa pgsize 0x%zx count %zu\n", - iova, &paddr, pgsize, count); - - if (ops->map_pages) { - ret = ops->map_pages(domain, iova, paddr, pgsize, count, prot, - gfp, mapped); - } else { - ret = ops->map(domain, iova, paddr, pgsize, prot, gfp); - *mapped = ret ? 0 : pgsize; - } - - return ret; -} - static int __iommu_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t paddr, size_t size, int prot, gfp_t gfp) { @@ -2543,8 +2519,7 @@ static int __iommu_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t orig_paddr = paddr; int ret = 0; - if (unlikely(!(ops->map || ops->map_pages) || - domain->pgsize_bitmap == 0UL)) + if (unlikely(!ops->map_pages || domain->pgsize_bitmap == 0UL)) return -ENODEV; if (unlikely(!(domain->type & __IOMMU_DOMAIN_PAGING))) @@ -2567,10 +2542,14 @@ static int __iommu_map(struct iommu_domain *domain, unsigned long iova, pr_debug("map: iova 0x%lx pa %pa size 0x%zx\n", iova, &paddr, size); while (size) { - size_t mapped = 0; + size_t pgsize, count, mapped = 0; + + pgsize = iommu_pgsize(domain, iova, paddr, size, &count); - ret = __iommu_map_pages(domain, iova, paddr, size, prot, gfp, - &mapped); + pr_debug("mapping: iova 0x%lx pa %pa pgsize 0x%zx count %zu\n", + iova, &paddr, pgsize, count); + ret = ops->map_pages(domain, iova, paddr, pgsize, count, prot, + gfp, &mapped); /* * Some pages may have been mapped, even if an error occurred, * so we should account for those so they can be unmapped. @@ -2614,19 +2593,6 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova, } EXPORT_SYMBOL_GPL(iommu_map); -static size_t __iommu_unmap_pages(struct iommu_domain *domain, - unsigned long iova, size_t size, - struct iommu_iotlb_gather *iotlb_gather) -{ - const struct iommu_domain_ops *ops = domain->ops; - size_t pgsize, count; - - pgsize = iommu_pgsize(domain, iova, iova, size, &count); - return ops->unmap_pages ? - ops->unmap_pages(domain, iova, pgsize, count, iotlb_gather) : - ops->unmap(domain, iova, pgsize, iotlb_gather); -} - static size_t __iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size, struct iommu_iotlb_gather *iotlb_gather) @@ -2636,8 +2602,7 @@ static size_t __iommu_unmap(struct iommu_domain *domain, unsigned long orig_iova = iova; unsigned int min_pagesz; - if (unlikely(!(ops->unmap || ops->unmap_pages) || - domain->pgsize_bitmap == 0UL)) + if (unlikely(!ops->unmap_pages || domain->pgsize_bitmap == 0UL)) return 0; if (unlikely(!(domain->type & __IOMMU_DOMAIN_PAGING))) @@ -2664,9 +2629,10 @@ static size_t __iommu_unmap(struct iommu_domain *domain, * or we hit an area that isn't mapped. */ while (unmapped < size) { - unmapped_page = __iommu_unmap_pages(domain, iova, - size - unmapped, - iotlb_gather); + size_t pgsize, count; + + pgsize = iommu_pgsize(domain, iova, iova, size - unmapped, &count); + unmapped_page = ops->unmap_pages(domain, iova, pgsize, count, iotlb_gather); if (!unmapped_page) break; diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 5b693be3d35fc..64bd20142cbed 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -322,10 +322,8 @@ struct iommu_ops { * * ENODEV - device specific errors, not able to be attached * * - treated as ENODEV by the caller. Use is discouraged * @set_dev_pasid: set an iommu domain to a pasid of device - * @map: map a physically contiguous memory region to an iommu domain * @map_pages: map a physically contiguous set of pages of the same size to * an iommu domain. - * @unmap: unmap a physically contiguous memory region from an iommu domain * @unmap_pages: unmap a number of pages of the same size from an iommu domain * @flush_iotlb_all: Synchronously flush all hardware TLBs for this domain * @iotlb_sync_map: Sync mappings created recently using @map to the hardware @@ -344,13 +342,9 @@ struct iommu_domain_ops { int (*set_dev_pasid)(struct iommu_domain *domain, struct device *dev, ioasid_t pasid); - int (*map)(struct iommu_domain *domain, unsigned long iova, - phys_addr_t paddr, size_t size, int prot, gfp_t gfp); int (*map_pages)(struct iommu_domain *domain, unsigned long iova, phys_addr_t paddr, size_t pgsize, size_t pgcount, int prot, gfp_t gfp, size_t *mapped); - size_t (*unmap)(struct iommu_domain *domain, unsigned long iova, - size_t size, struct iommu_iotlb_gather *iotlb_gather); size_t (*unmap_pages)(struct iommu_domain *domain, unsigned long iova, size_t pgsize, size_t pgcount, struct iommu_iotlb_gather *iotlb_gather); -- GitLab From afad94a93ef12887390d67aa9b6dd6be2657712f Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Tue, 12 Sep 2023 17:18:44 +0100 Subject: [PATCH 0156/1451] iommu: Improve map/unmap sanity checks The current checks for the __IOMMU_DOMAIN_PAGING capability seem a bit stifled, since it is quite likely now that a non-paging domain won't have a pgsize_bitmap and/or mapping ops, and thus get caught by the earlier condition anyway. Swap them around to test the more fundamental condition first, then we can reasonably also upgrade the other to a WARN_ON, since if a driver does ever expose a paging domain without the means to actually page, it's clearly very broken. Signed-off-by: Robin Murphy Link: https://lore.kernel.org/r/524db1ec0139c964d26928a6a264945aa66d010c.1694525662.git.robin.murphy@arm.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 865fa4f179a8f..b2d08e422942b 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -2519,12 +2519,12 @@ static int __iommu_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t orig_paddr = paddr; int ret = 0; - if (unlikely(!ops->map_pages || domain->pgsize_bitmap == 0UL)) - return -ENODEV; - if (unlikely(!(domain->type & __IOMMU_DOMAIN_PAGING))) return -EINVAL; + if (WARN_ON(!ops->map_pages || domain->pgsize_bitmap == 0UL)) + return -ENODEV; + /* find out the minimum page size supported */ min_pagesz = 1 << __ffs(domain->pgsize_bitmap); @@ -2602,10 +2602,10 @@ static size_t __iommu_unmap(struct iommu_domain *domain, unsigned long orig_iova = iova; unsigned int min_pagesz; - if (unlikely(!ops->unmap_pages || domain->pgsize_bitmap == 0UL)) + if (unlikely(!(domain->type & __IOMMU_DOMAIN_PAGING))) return 0; - if (unlikely(!(domain->type & __IOMMU_DOMAIN_PAGING))) + if (WARN_ON(!ops->unmap_pages || domain->pgsize_bitmap == 0UL)) return 0; /* find out the minimum page size supported */ -- GitLab From 911aa1245da83ff5e76d33bb612d8b5a3f2ec4a5 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Tue, 12 Sep 2023 17:28:05 +0100 Subject: [PATCH 0157/1451] iommu/iova: Make the rcache depot scale better The algorithm in the original paper specifies the storage of full magazines in the depot as an unbounded list rather than a fixed-size array. It turns out to be pretty straightforward to do this in our implementation with no significant loss of efficiency. This allows the depot to scale up to the working set sizes of larger systems, while also potentially saving some memory on smaller ones too. Since this involves touching struct iova_magazine with the requisite care, we may as well reinforce the comment with a proper assertion too. Reviewed-by: John Garry Reviewed-by: Jerry Snitselaar Signed-off-by: Robin Murphy Link: https://lore.kernel.org/r/f597aa72fc3e1d315bc4574af0ce0ebe5c31cd22.1694535580.git.robin.murphy@arm.com Signed-off-by: Joerg Roedel --- drivers/iommu/iova.c | 65 ++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c index 10b964600948c..dd2309e9a6c5d 100644 --- a/drivers/iommu/iova.c +++ b/drivers/iommu/iova.c @@ -622,15 +622,19 @@ EXPORT_SYMBOL_GPL(reserve_iova); /* * As kmalloc's buffer size is fixed to power of 2, 127 is chosen to * assure size of 'iova_magazine' to be 1024 bytes, so that no memory - * will be wasted. + * will be wasted. Since only full magazines are inserted into the depot, + * we don't need to waste PFN capacity on a separate list head either. */ #define IOVA_MAG_SIZE 127 -#define MAX_GLOBAL_MAGS 32 /* magazines per bin */ struct iova_magazine { - unsigned long size; + union { + unsigned long size; + struct iova_magazine *next; + }; unsigned long pfns[IOVA_MAG_SIZE]; }; +static_assert(!(sizeof(struct iova_magazine) & (sizeof(struct iova_magazine) - 1))); struct iova_cpu_rcache { spinlock_t lock; @@ -640,8 +644,7 @@ struct iova_cpu_rcache { struct iova_rcache { spinlock_t lock; - unsigned long depot_size; - struct iova_magazine *depot[MAX_GLOBAL_MAGS]; + struct iova_magazine *depot; struct iova_cpu_rcache __percpu *cpu_rcaches; }; @@ -717,6 +720,21 @@ static void iova_magazine_push(struct iova_magazine *mag, unsigned long pfn) mag->pfns[mag->size++] = pfn; } +static struct iova_magazine *iova_depot_pop(struct iova_rcache *rcache) +{ + struct iova_magazine *mag = rcache->depot; + + rcache->depot = mag->next; + mag->size = IOVA_MAG_SIZE; + return mag; +} + +static void iova_depot_push(struct iova_rcache *rcache, struct iova_magazine *mag) +{ + mag->next = rcache->depot; + rcache->depot = mag; +} + int iova_domain_init_rcaches(struct iova_domain *iovad) { unsigned int cpu; @@ -734,7 +752,6 @@ int iova_domain_init_rcaches(struct iova_domain *iovad) rcache = &iovad->rcaches[i]; spin_lock_init(&rcache->lock); - rcache->depot_size = 0; rcache->cpu_rcaches = __alloc_percpu(sizeof(*cpu_rcache), cache_line_size()); if (!rcache->cpu_rcaches) { @@ -776,7 +793,6 @@ static bool __iova_rcache_insert(struct iova_domain *iovad, struct iova_rcache *rcache, unsigned long iova_pfn) { - struct iova_magazine *mag_to_free = NULL; struct iova_cpu_rcache *cpu_rcache; bool can_insert = false; unsigned long flags; @@ -794,12 +810,7 @@ static bool __iova_rcache_insert(struct iova_domain *iovad, if (new_mag) { spin_lock(&rcache->lock); - if (rcache->depot_size < MAX_GLOBAL_MAGS) { - rcache->depot[rcache->depot_size++] = - cpu_rcache->loaded; - } else { - mag_to_free = cpu_rcache->loaded; - } + iova_depot_push(rcache, cpu_rcache->loaded); spin_unlock(&rcache->lock); cpu_rcache->loaded = new_mag; @@ -812,11 +823,6 @@ static bool __iova_rcache_insert(struct iova_domain *iovad, spin_unlock_irqrestore(&cpu_rcache->lock, flags); - if (mag_to_free) { - iova_magazine_free_pfns(mag_to_free, iovad); - iova_magazine_free(mag_to_free); - } - return can_insert; } @@ -854,9 +860,9 @@ static unsigned long __iova_rcache_get(struct iova_rcache *rcache, has_pfn = true; } else { spin_lock(&rcache->lock); - if (rcache->depot_size > 0) { + if (rcache->depot) { iova_magazine_free(cpu_rcache->loaded); - cpu_rcache->loaded = rcache->depot[--rcache->depot_size]; + cpu_rcache->loaded = iova_depot_pop(rcache); has_pfn = true; } spin_unlock(&rcache->lock); @@ -895,9 +901,8 @@ static void free_iova_rcaches(struct iova_domain *iovad) struct iova_rcache *rcache; struct iova_cpu_rcache *cpu_rcache; unsigned int cpu; - int i, j; - for (i = 0; i < IOVA_RANGE_CACHE_MAX_SIZE; ++i) { + for (int i = 0; i < IOVA_RANGE_CACHE_MAX_SIZE; ++i) { rcache = &iovad->rcaches[i]; if (!rcache->cpu_rcaches) break; @@ -907,8 +912,8 @@ static void free_iova_rcaches(struct iova_domain *iovad) iova_magazine_free(cpu_rcache->prev); } free_percpu(rcache->cpu_rcaches); - for (j = 0; j < rcache->depot_size; ++j) - iova_magazine_free(rcache->depot[j]); + while (rcache->depot) + iova_magazine_free(iova_depot_pop(rcache)); } kfree(iovad->rcaches); @@ -942,16 +947,16 @@ static void free_global_cached_iovas(struct iova_domain *iovad) { struct iova_rcache *rcache; unsigned long flags; - int i, j; - for (i = 0; i < IOVA_RANGE_CACHE_MAX_SIZE; ++i) { + for (int i = 0; i < IOVA_RANGE_CACHE_MAX_SIZE; ++i) { rcache = &iovad->rcaches[i]; spin_lock_irqsave(&rcache->lock, flags); - for (j = 0; j < rcache->depot_size; ++j) { - iova_magazine_free_pfns(rcache->depot[j], iovad); - iova_magazine_free(rcache->depot[j]); + while (rcache->depot) { + struct iova_magazine *mag = iova_depot_pop(rcache); + + iova_magazine_free_pfns(mag, iovad); + iova_magazine_free(mag); } - rcache->depot_size = 0; spin_unlock_irqrestore(&rcache->lock, flags); } } -- GitLab From 233045378dbbc0a7346127d19a54d4f91e0bd855 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Tue, 12 Sep 2023 17:28:06 +0100 Subject: [PATCH 0158/1451] iommu/iova: Manage the depot list size Automatically scaling the depot up to suit the peak capacity of a workload is all well and good, but it would be nice to have a way to scale it back down again if the workload changes. To that end, add backround reclaim that will gradually free surplus magazines if the depot size remains above a reasonable threshold for long enough. Reviewed-by: Jerry Snitselaar Signed-off-by: Robin Murphy Link: https://lore.kernel.org/r/03170665c56d89c6ce6081246b47f68d4e483308.1694535580.git.robin.murphy@arm.com Signed-off-by: Joerg Roedel --- drivers/iommu/iova.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c index dd2309e9a6c5d..d30e453d0fb4b 100644 --- a/drivers/iommu/iova.c +++ b/drivers/iommu/iova.c @@ -11,6 +11,7 @@ #include #include #include +#include /* The anchor node sits above the top of the usable address space */ #define IOVA_ANCHOR ~0UL @@ -627,6 +628,8 @@ EXPORT_SYMBOL_GPL(reserve_iova); */ #define IOVA_MAG_SIZE 127 +#define IOVA_DEPOT_DELAY msecs_to_jiffies(100) + struct iova_magazine { union { unsigned long size; @@ -644,8 +647,11 @@ struct iova_cpu_rcache { struct iova_rcache { spinlock_t lock; + unsigned int depot_size; struct iova_magazine *depot; struct iova_cpu_rcache __percpu *cpu_rcaches; + struct iova_domain *iovad; + struct delayed_work work; }; static struct iova_magazine *iova_magazine_alloc(gfp_t flags) @@ -726,6 +732,7 @@ static struct iova_magazine *iova_depot_pop(struct iova_rcache *rcache) rcache->depot = mag->next; mag->size = IOVA_MAG_SIZE; + rcache->depot_size--; return mag; } @@ -733,6 +740,25 @@ static void iova_depot_push(struct iova_rcache *rcache, struct iova_magazine *ma { mag->next = rcache->depot; rcache->depot = mag; + rcache->depot_size++; +} + +static void iova_depot_work_func(struct work_struct *work) +{ + struct iova_rcache *rcache = container_of(work, typeof(*rcache), work.work); + struct iova_magazine *mag = NULL; + unsigned long flags; + + spin_lock_irqsave(&rcache->lock, flags); + if (rcache->depot_size > num_online_cpus()) + mag = iova_depot_pop(rcache); + spin_unlock_irqrestore(&rcache->lock, flags); + + if (mag) { + iova_magazine_free_pfns(mag, rcache->iovad); + iova_magazine_free(mag); + schedule_delayed_work(&rcache->work, IOVA_DEPOT_DELAY); + } } int iova_domain_init_rcaches(struct iova_domain *iovad) @@ -752,6 +778,8 @@ int iova_domain_init_rcaches(struct iova_domain *iovad) rcache = &iovad->rcaches[i]; spin_lock_init(&rcache->lock); + rcache->iovad = iovad; + INIT_DELAYED_WORK(&rcache->work, iova_depot_work_func); rcache->cpu_rcaches = __alloc_percpu(sizeof(*cpu_rcache), cache_line_size()); if (!rcache->cpu_rcaches) { @@ -812,6 +840,7 @@ static bool __iova_rcache_insert(struct iova_domain *iovad, spin_lock(&rcache->lock); iova_depot_push(rcache, cpu_rcache->loaded); spin_unlock(&rcache->lock); + schedule_delayed_work(&rcache->work, IOVA_DEPOT_DELAY); cpu_rcache->loaded = new_mag; can_insert = true; @@ -912,6 +941,7 @@ static void free_iova_rcaches(struct iova_domain *iovad) iova_magazine_free(cpu_rcache->prev); } free_percpu(rcache->cpu_rcaches); + cancel_delayed_work_sync(&rcache->work); while (rcache->depot) iova_magazine_free(iova_depot_pop(rcache)); } -- GitLab From ade4bec9e18294dd2f754007cfdc5d3bc294400d Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 21 Sep 2023 09:21:34 +0000 Subject: [PATCH 0159/1451] iommu/amd: Remove unused amd_io_pgtable.pt_root variable It has been no longer used since the commit 6eedb59c18a3 ("iommu/amd: Remove amd_iommu_domain_get_pgtable"). Signed-off-by: Suravee Suthikulpanit Signed-off-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20230921092147.5930-2-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/amd_iommu.h | 1 - drivers/iommu/amd/amd_iommu_types.h | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h index e2857109e9660..c5090e00b3aa7 100644 --- a/drivers/iommu/amd/amd_iommu.h +++ b/drivers/iommu/amd/amd_iommu.h @@ -105,7 +105,6 @@ static inline void *iommu_phys_to_virt(unsigned long paddr) static inline void amd_iommu_domain_set_pt_root(struct protection_domain *domain, u64 root) { - atomic64_set(&domain->iop.pt_root, root); domain->iop.root = (u64 *)(root & PAGE_MASK); domain->iop.mode = root & 7; /* lowest 3 bits encode pgtable mode */ } diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index 7dc30c2b56b30..081d8d0f29d52 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -544,7 +544,6 @@ struct amd_io_pgtable { struct io_pgtable iop; int mode; u64 *root; - atomic64_t pt_root; /* pgtable root and pgtable mode */ u64 *pgd; /* v2 pgtable pgd pointer */ }; -- GitLab From 75e6d7edfdcc540fc59d7bb289bd8b68ca11aa1c Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 21 Sep 2023 09:21:35 +0000 Subject: [PATCH 0160/1451] iommu/amd: Consolidate timeout pre-define to amd_iommu_type.h To allow inclusion in other files in subsequent patches. Signed-off-by: Suravee Suthikulpanit Signed-off-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20230921092147.5930-3-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/amd_iommu_types.h | 4 ++++ drivers/iommu/amd/init.c | 10 ++++------ drivers/iommu/amd/iommu.c | 2 -- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index 081d8d0f29d52..a8d264026f7f5 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -451,6 +451,10 @@ #define PD_IOMMUV2_MASK BIT(3) /* domain has gcr3 table */ #define PD_GIOV_MASK BIT(4) /* domain enable GIOV support */ +/* Timeout stuff */ +#define LOOP_TIMEOUT 100000 +#define MMIO_STATUS_TIMEOUT 2000000 + extern bool amd_iommu_dump; #define DUMP_printk(format, arg...) \ do { \ diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index 45efb7e5d7254..852e40b13d203 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -83,8 +83,6 @@ #define ACPI_DEVFLAG_LINT1 0x80 #define ACPI_DEVFLAG_ATSDIS 0x10000000 -#define LOOP_TIMEOUT 2000000 - #define IVRS_GET_SBDF_ID(seg, bus, dev, fn) (((seg & 0xffff) << 16) | ((bus & 0xff) << 8) \ | ((dev & 0x1f) << 3) | (fn & 0x7)) @@ -985,14 +983,14 @@ static int iommu_ga_log_enable(struct amd_iommu *iommu) iommu_feature_enable(iommu, CONTROL_GAINT_EN); iommu_feature_enable(iommu, CONTROL_GALOG_EN); - for (i = 0; i < LOOP_TIMEOUT; ++i) { + for (i = 0; i < MMIO_STATUS_TIMEOUT; ++i) { status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET); if (status & (MMIO_STATUS_GALOG_RUN_MASK)) break; udelay(10); } - if (WARN_ON(i >= LOOP_TIMEOUT)) + if (WARN_ON(i >= MMIO_STATUS_TIMEOUT)) return -EINVAL; return 0; @@ -2900,14 +2898,14 @@ static void enable_iommus_vapic(void) * Need to set and poll check the GALOGRun bit to zero before * we can set/ modify GA Log registers safely. */ - for (i = 0; i < LOOP_TIMEOUT; ++i) { + for (i = 0; i < MMIO_STATUS_TIMEOUT; ++i) { status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET); if (!(status & MMIO_STATUS_GALOG_RUN_MASK)) break; udelay(10); } - if (WARN_ON(i >= LOOP_TIMEOUT)) + if (WARN_ON(i >= MMIO_STATUS_TIMEOUT)) return; } diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 95bd7c25ba6f3..6fa6a0527d7ba 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -44,8 +44,6 @@ #define CMD_SET_TYPE(cmd, t) ((cmd)->data[1] |= ((t) << 28)) -#define LOOP_TIMEOUT 100000 - /* IO virtual address start page frame number */ #define IOVA_START_PFN (1) #define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT) -- GitLab From ba7d263b7749f8e7f227d7357963632711b5c6ea Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 21 Sep 2023 09:21:36 +0000 Subject: [PATCH 0161/1451] iommu/amd: Consolidate logic to allocate protection domain Move the logic into the common caller function to simplify the code. No functional changes intended. Signed-off-by: Suravee Suthikulpanit Signed-off-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20230921092147.5930-4-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/iommu.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 6fa6a0527d7ba..c99611139ab55 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -2046,12 +2046,6 @@ static int protection_domain_init_v1(struct protection_domain *domain, int mode) BUG_ON(mode < PAGE_MODE_NONE || mode > PAGE_MODE_6_LEVEL); - spin_lock_init(&domain->lock); - domain->id = domain_id_alloc(); - if (!domain->id) - return -ENOMEM; - INIT_LIST_HEAD(&domain->dev_list); - if (mode != PAGE_MODE_NONE) { pt_root = (void *)get_zeroed_page(GFP_KERNEL); if (!pt_root) { @@ -2067,12 +2061,6 @@ static int protection_domain_init_v1(struct protection_domain *domain, int mode) static int protection_domain_init_v2(struct protection_domain *domain) { - spin_lock_init(&domain->lock); - domain->id = domain_id_alloc(); - if (!domain->id) - return -ENOMEM; - INIT_LIST_HEAD(&domain->dev_list); - domain->flags |= PD_GIOV_MASK; domain->domain.pgsize_bitmap = AMD_IOMMU_PGSIZES_V2; @@ -2112,6 +2100,13 @@ static struct protection_domain *protection_domain_alloc(unsigned int type) if (!domain) return NULL; + domain->id = domain_id_alloc(); + if (!domain->id) + goto out_err; + + spin_lock_init(&domain->lock); + INIT_LIST_HEAD(&domain->dev_list); + switch (pgtable) { case AMD_IOMMU_V1: ret = protection_domain_init_v1(domain, mode); -- GitLab From bac05772fa9912195b2029ab757fe86773c7ff00 Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Thu, 21 Sep 2023 09:21:37 +0000 Subject: [PATCH 0162/1451] iommu/amd: Refactor protection domain allocation code To replace if-else with switch-case statement due to increasing number of domain types. No functional changes intended. Signed-off-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20230921092147.5930-5-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/iommu.c | 45 +++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index c99611139ab55..bc1fa6e43794c 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -2078,24 +2078,8 @@ static struct protection_domain *protection_domain_alloc(unsigned int type) struct io_pgtable_ops *pgtbl_ops; struct protection_domain *domain; int pgtable; - int mode = DEFAULT_PGTABLE_LEVEL; int ret; - /* - * Force IOMMU v1 page table when iommu=pt and - * when allocating domain for pass-through devices. - */ - if (type == IOMMU_DOMAIN_IDENTITY) { - pgtable = AMD_IOMMU_V1; - mode = PAGE_MODE_NONE; - } else if (type == IOMMU_DOMAIN_UNMANAGED) { - pgtable = AMD_IOMMU_V1; - } else if (type == IOMMU_DOMAIN_DMA || type == IOMMU_DOMAIN_DMA_FQ) { - pgtable = amd_iommu_pgtable; - } else { - return NULL; - } - domain = kzalloc(sizeof(*domain), GFP_KERNEL); if (!domain) return NULL; @@ -2106,27 +2090,42 @@ static struct protection_domain *protection_domain_alloc(unsigned int type) spin_lock_init(&domain->lock); INIT_LIST_HEAD(&domain->dev_list); + domain->nid = NUMA_NO_NODE; + + switch (type) { + /* No need to allocate io pgtable ops in passthrough mode */ + case IOMMU_DOMAIN_IDENTITY: + return domain; + case IOMMU_DOMAIN_DMA: + case IOMMU_DOMAIN_DMA_FQ: + pgtable = amd_iommu_pgtable; + break; + /* + * Force IOMMU v1 page table when allocating + * domain for pass-through devices. + */ + case IOMMU_DOMAIN_UNMANAGED: + pgtable = AMD_IOMMU_V1; + break; + default: + goto out_err; + } switch (pgtable) { case AMD_IOMMU_V1: - ret = protection_domain_init_v1(domain, mode); + ret = protection_domain_init_v1(domain, DEFAULT_PGTABLE_LEVEL); break; case AMD_IOMMU_V2: ret = protection_domain_init_v2(domain); break; default: ret = -EINVAL; + break; } if (ret) goto out_err; - /* No need to allocate io pgtable ops in passthrough mode */ - if (type == IOMMU_DOMAIN_IDENTITY) - return domain; - - domain->nid = NUMA_NO_NODE; - pgtbl_ops = alloc_io_pgtable_ops(pgtable, &domain->iop.pgtbl_cfg, domain); if (!pgtbl_ops) { domain_id_free(domain->id); -- GitLab From 206fb06dc54a7b3df0107a96e221e7b49661059d Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 21 Sep 2023 09:21:38 +0000 Subject: [PATCH 0163/1451] iommu/amd: Introduce helper functions for managing GCR3 table Refactor domain_enable_v2() into helper functions for managing GCR3 table (i.e. setup_gcr3_table() and get_gcr3_levels()), which will be used in subsequent patches. Also re-arrange code and remove forward declaration. Signed-off-by: Suravee Suthikulpanit Co-developed-by: Vasant Hegde Signed-off-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20230921092147.5930-6-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/iommu.c | 65 +++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index bc1fa6e43794c..46a10b489cf59 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -77,7 +77,6 @@ struct iommu_cmd { struct kmem_cache *amd_iommu_irq_cache; static void detach_device(struct device *dev); -static int domain_enable_v2(struct protection_domain *domain, int pasids); /**************************************************************************** * @@ -1575,6 +1574,42 @@ static void free_gcr3_table(struct protection_domain *domain) free_page((unsigned long)domain->gcr3_tbl); } +/* + * Number of GCR3 table levels required. Level must be 4-Kbyte + * page and can contain up to 512 entries. + */ +static int get_gcr3_levels(int pasids) +{ + int levels; + + if (pasids == -1) + return amd_iommu_max_glx_val; + + levels = get_count_order(pasids); + + return levels ? (DIV_ROUND_UP(levels, 9) - 1) : levels; +} + +/* Note: This function expects iommu_domain->lock to be held prior calling the function. */ +static int setup_gcr3_table(struct protection_domain *domain, int pasids) +{ + int levels = get_gcr3_levels(pasids); + + if (levels > amd_iommu_max_glx_val) + return -EINVAL; + + domain->gcr3_tbl = alloc_pgtable_page(domain->nid, GFP_ATOMIC); + if (domain->gcr3_tbl == NULL) + return -ENOMEM; + + domain->glx = levels; + domain->flags |= PD_IOMMUV2_MASK; + + amd_iommu_domain_update(domain); + + return 0; +} + static void set_dte_entry(struct amd_iommu *iommu, u16 devid, struct protection_domain *domain, bool ats, bool ppr) { @@ -2065,7 +2100,7 @@ static int protection_domain_init_v2(struct protection_domain *domain) domain->domain.pgsize_bitmap = AMD_IOMMU_PGSIZES_V2; - if (domain_enable_v2(domain, 1)) { + if (setup_gcr3_table(domain, 1)) { domain_id_free(domain->id); return -ENOMEM; } @@ -2514,30 +2549,6 @@ void amd_iommu_domain_direct_map(struct iommu_domain *dom) } EXPORT_SYMBOL(amd_iommu_domain_direct_map); -/* Note: This function expects iommu_domain->lock to be held prior calling the function. */ -static int domain_enable_v2(struct protection_domain *domain, int pasids) -{ - int levels; - - /* Number of GCR3 table levels required */ - for (levels = 0; (pasids - 1) & ~0x1ff; pasids >>= 9) - levels += 1; - - if (levels > amd_iommu_max_glx_val) - return -EINVAL; - - domain->gcr3_tbl = (void *)get_zeroed_page(GFP_ATOMIC); - if (domain->gcr3_tbl == NULL) - return -ENOMEM; - - domain->glx = levels; - domain->flags |= PD_IOMMUV2_MASK; - - amd_iommu_domain_update(domain); - - return 0; -} - int amd_iommu_domain_enable_v2(struct iommu_domain *dom, int pasids) { struct protection_domain *pdom = to_pdomain(dom); @@ -2556,7 +2567,7 @@ int amd_iommu_domain_enable_v2(struct iommu_domain *dom, int pasids) goto out; if (!pdom->gcr3_tbl) - ret = domain_enable_v2(pdom, pasids); + ret = setup_gcr3_table(pdom, pasids); out: spin_unlock_irqrestore(&pdom->lock, flags); -- GitLab From 4c721d6a085ca7baa4289bcf786c71684b2ef281 Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Thu, 21 Sep 2023 09:21:39 +0000 Subject: [PATCH 0164/1451] iommu/amd: Do not set amd_iommu_pgtable in pass-through mode Since AMD IOMMU page table is not used in passthrough mode, switching to v1 page table is not required. Therefore, remove redundant amd_iommu_pgtable update and misleading warning message. Signed-off-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20230921092147.5930-7-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/init.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index 852e40b13d203..2b01dfde6cab1 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -2134,9 +2134,6 @@ static int __init iommu_init_pci(struct amd_iommu *iommu) !iommu_feature(iommu, FEATURE_GT)) { pr_warn("Cannot enable v2 page table for DMA-API. Fallback to v1.\n"); amd_iommu_pgtable = AMD_IOMMU_V1; - } else if (iommu_default_passthrough()) { - pr_warn("V2 page table doesn't support passthrough mode. Fallback to v1.\n"); - amd_iommu_pgtable = AMD_IOMMU_V1; } } -- GitLab From 45677ab1e5ca65622b35cc231c5d31c699cfaefe Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 21 Sep 2023 09:21:40 +0000 Subject: [PATCH 0165/1451] iommu/amd: Miscellaneous clean up when free domain * Use the protection_domain_free() helper function to free domain. The function has been modified to also free memory used for the v1 and v2 page tables. Also clear gcr3 table in v2 page table free path. * Refactor code into cleanup_domain() for reusability. Change BUG_ON to WARN_ON in cleanup path. * Protection domain dev_cnt should be read when the domain is locked. Signed-off-by: Suravee Suthikulpanit Co-developed-by: Vasant Hegde Signed-off-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20230921092147.5930-8-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/io_pgtable_v2.c | 8 +++--- drivers/iommu/amd/iommu.c | 44 +++++++++++++++---------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/iommu/amd/io_pgtable_v2.c b/drivers/iommu/amd/io_pgtable_v2.c index e9ef2e0a62f67..f818a7e254d42 100644 --- a/drivers/iommu/amd/io_pgtable_v2.c +++ b/drivers/iommu/amd/io_pgtable_v2.c @@ -363,10 +363,10 @@ static void v2_free_pgtable(struct io_pgtable *iop) if (!(pdom->flags & PD_IOMMUV2_MASK)) return; - /* - * Make changes visible to IOMMUs. No need to clear gcr3 entry - * as gcr3 table is already freed. - */ + /* Clear gcr3 entry */ + amd_iommu_domain_clear_gcr3(&pdom->domain, 0); + + /* Make changes visible to IOMMUs */ amd_iommu_domain_update(pdom); /* Free page table */ diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 46a10b489cf59..0dd8390113afa 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -2047,9 +2047,11 @@ void amd_iommu_domain_update(struct protection_domain *domain) static void cleanup_domain(struct protection_domain *domain) { struct iommu_dev_data *entry; - unsigned long flags; - spin_lock_irqsave(&domain->lock, flags); + lockdep_assert_held(&domain->lock); + + if (!domain->dev_cnt) + return; while (!list_empty(&domain->dev_list)) { entry = list_first_entry(&domain->dev_list, @@ -2057,8 +2059,7 @@ static void cleanup_domain(struct protection_domain *domain) BUG_ON(!entry->domain); do_detach(entry); } - - spin_unlock_irqrestore(&domain->lock, flags); + WARN_ON(domain->dev_cnt != 0); } static void protection_domain_free(struct protection_domain *domain) @@ -2069,6 +2070,12 @@ static void protection_domain_free(struct protection_domain *domain) if (domain->iop.pgtbl_cfg.tlb) free_io_pgtable_ops(&domain->iop.iop.ops); + if (domain->flags & PD_IOMMUV2_MASK) + free_gcr3_table(domain); + + if (domain->iop.root) + free_page((unsigned long)domain->iop.root); + if (domain->id) domain_id_free(domain->id); @@ -2083,10 +2090,8 @@ static int protection_domain_init_v1(struct protection_domain *domain, int mode) if (mode != PAGE_MODE_NONE) { pt_root = (void *)get_zeroed_page(GFP_KERNEL); - if (!pt_root) { - domain_id_free(domain->id); + if (!pt_root) return -ENOMEM; - } } amd_iommu_domain_set_pgtable(domain, pt_root, mode); @@ -2100,10 +2105,8 @@ static int protection_domain_init_v2(struct protection_domain *domain) domain->domain.pgsize_bitmap = AMD_IOMMU_PGSIZES_V2; - if (setup_gcr3_table(domain, 1)) { - domain_id_free(domain->id); + if (setup_gcr3_table(domain, 1)) return -ENOMEM; - } return 0; } @@ -2162,14 +2165,12 @@ static struct protection_domain *protection_domain_alloc(unsigned int type) goto out_err; pgtbl_ops = alloc_io_pgtable_ops(pgtable, &domain->iop.pgtbl_cfg, domain); - if (!pgtbl_ops) { - domain_id_free(domain->id); + if (!pgtbl_ops) goto out_err; - } return domain; out_err: - kfree(domain); + protection_domain_free(domain); return NULL; } @@ -2207,19 +2208,18 @@ static struct iommu_domain *amd_iommu_domain_alloc(unsigned type) static void amd_iommu_domain_free(struct iommu_domain *dom) { struct protection_domain *domain; + unsigned long flags; - domain = to_pdomain(dom); + if (!dom) + return; - if (domain->dev_cnt > 0) - cleanup_domain(domain); + domain = to_pdomain(dom); - BUG_ON(domain->dev_cnt != 0); + spin_lock_irqsave(&domain->lock, flags); - if (!dom) - return; + cleanup_domain(domain); - if (domain->flags & PD_IOMMUV2_MASK) - free_gcr3_table(domain); + spin_unlock_irqrestore(&domain->lock, flags); protection_domain_free(domain); } -- GitLab From 7b7563a93437ef945c829538da28f0095f1603ec Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 21 Sep 2023 09:21:41 +0000 Subject: [PATCH 0166/1451] iommu/amd: Consolidate feature detection and reporting logic Currently, IOMMU driver assumes capabilities on all IOMMU instances to be homogeneous. During early_amd_iommu_init(), the driver probes all IVHD blocks and do sanity check to make sure that only features common among all IOMMU instances are supported. This is tracked in the global amd_iommu_efr and amd_iommu_efr2, which should be used whenever the driver need to check hardware capabilities. Therefore, introduce check_feature() and check_feature2(), and modify the driver to adopt the new helper functions. In addition, clean up the print_iommu_info() to avoid reporting redundant EFR/EFR2 for each IOMMU instance. Signed-off-by: Suravee Suthikulpanit Signed-off-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20230921092147.5930-9-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/amd_iommu.h | 17 ++++-- drivers/iommu/amd/amd_iommu_types.h | 4 ++ drivers/iommu/amd/init.c | 89 ++++++++++++----------------- drivers/iommu/amd/iommu.c | 4 +- 4 files changed, 54 insertions(+), 60 deletions(-) diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h index c5090e00b3aa7..e1b0eeead0746 100644 --- a/drivers/iommu/amd/amd_iommu.h +++ b/drivers/iommu/amd/amd_iommu.h @@ -87,9 +87,19 @@ static inline bool is_rd890_iommu(struct pci_dev *pdev) (pdev->device == PCI_DEVICE_ID_RD890_IOMMU); } -static inline bool iommu_feature(struct amd_iommu *iommu, u64 mask) +static inline bool check_feature(u64 mask) { - return !!(iommu->features & mask); + return (amd_iommu_efr & mask); +} + +static inline bool check_feature2(u64 mask) +{ + return (amd_iommu_efr2 & mask); +} + +static inline int check_feature_gpt_level(void) +{ + return ((amd_iommu_efr >> FEATURE_GATS_SHIFT) & FEATURE_GATS_MASK); } static inline u64 iommu_virt_to_phys(void *vaddr) @@ -145,8 +155,5 @@ void amd_iommu_domain_set_pgtable(struct protection_domain *domain, u64 *root, int mode); struct dev_table_entry *get_dev_table(struct amd_iommu *iommu); -extern u64 amd_iommu_efr; -extern u64 amd_iommu_efr2; - extern bool amd_iommu_snp_en; #endif diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index a8d264026f7f5..22bdfb0ddfb77 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -897,6 +897,10 @@ extern bool amd_iommu_force_isolation; /* Max levels of glxval supported */ extern int amd_iommu_max_glx_val; +/* Global EFR and EFR2 registers */ +extern u64 amd_iommu_efr; +extern u64 amd_iommu_efr2; + /* * This function flushes all internal caches of * the IOMMU used by this driver. diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index 2b01dfde6cab1..d0d506ad9cc95 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -270,7 +270,7 @@ int amd_iommu_get_num_iommus(void) * Iterate through all the IOMMUs to get common EFR * masks among all IOMMUs and warn if found inconsistency. */ -static void get_global_efr(void) +static __init void get_global_efr(void) { struct amd_iommu *iommu; @@ -302,16 +302,6 @@ static void get_global_efr(void) pr_info("Using global IVHD EFR:%#llx, EFR2:%#llx\n", amd_iommu_efr, amd_iommu_efr2); } -static bool check_feature_on_all_iommus(u64 mask) -{ - return !!(amd_iommu_efr & mask); -} - -static inline int check_feature_gpt_level(void) -{ - return ((amd_iommu_efr >> FEATURE_GATS_SHIFT) & FEATURE_GATS_MASK); -} - /* * For IVHD type 0x11/0x40, EFR is also available via IVHD. * Default to IVHD EFR since it is available sooner @@ -397,7 +387,7 @@ static void iommu_set_cwwb_range(struct amd_iommu *iommu) u64 start = iommu_virt_to_phys((void *)iommu->cmd_sem); u64 entry = start & PM_ADDR_MASK; - if (!check_feature_on_all_iommus(FEATURE_SNP)) + if (!check_feature(FEATURE_SNP)) return; /* Note: @@ -867,7 +857,7 @@ static void *__init iommu_alloc_4k_pages(struct amd_iommu *iommu, void *buf = (void *)__get_free_pages(gfp, order); if (buf && - check_feature_on_all_iommus(FEATURE_SNP) && + check_feature(FEATURE_SNP) && set_memory_4k((unsigned long)buf, (1 << order))) { free_pages((unsigned long)buf, order); buf = NULL; @@ -1046,7 +1036,7 @@ static void iommu_enable_xt(struct amd_iommu *iommu) static void iommu_enable_gt(struct amd_iommu *iommu) { - if (!iommu_feature(iommu, FEATURE_GT)) + if (!check_feature(FEATURE_GT)) return; iommu_feature_enable(iommu, CONTROL_GT_EN); @@ -1985,7 +1975,7 @@ static void init_iommu_perf_ctr(struct amd_iommu *iommu) u64 val; struct pci_dev *pdev = iommu->dev; - if (!iommu_feature(iommu, FEATURE_PC)) + if (!check_feature(FEATURE_PC)) return; amd_iommu_pc_present = true; @@ -2012,8 +2002,7 @@ static ssize_t amd_iommu_show_features(struct device *dev, struct device_attribute *attr, char *buf) { - struct amd_iommu *iommu = dev_to_amd_iommu(dev); - return sysfs_emit(buf, "%llx:%llx\n", iommu->features2, iommu->features); + return sysfs_emit(buf, "%llx:%llx\n", amd_iommu_efr, amd_iommu_efr2); } static DEVICE_ATTR(features, S_IRUGO, amd_iommu_show_features, NULL); @@ -2049,9 +2038,9 @@ static void __init late_iommu_features_init(struct amd_iommu *iommu) features = readq(iommu->mmio_base + MMIO_EXT_FEATURES); features2 = readq(iommu->mmio_base + MMIO_EXT_FEATURES2); - if (!iommu->features) { - iommu->features = features; - iommu->features2 = features2; + if (!amd_iommu_efr) { + amd_iommu_efr = features; + amd_iommu_efr2 = features2; return; } @@ -2059,12 +2048,12 @@ static void __init late_iommu_features_init(struct amd_iommu *iommu) * Sanity check and warn if EFR values from * IVHD and MMIO conflict. */ - if (features != iommu->features || - features2 != iommu->features2) { + if (features != amd_iommu_efr || + features2 != amd_iommu_efr2) { pr_warn(FW_WARN "EFR mismatch. Use IVHD EFR (%#llx : %#llx), EFR2 (%#llx : %#llx).\n", - features, iommu->features, - features2, iommu->features2); + features, amd_iommu_efr, + features2, amd_iommu_efr2); } } @@ -2090,12 +2079,12 @@ static int __init iommu_init_pci(struct amd_iommu *iommu) late_iommu_features_init(iommu); - if (iommu_feature(iommu, FEATURE_GT)) { + if (check_feature(FEATURE_GT)) { int glxval; u32 max_pasid; u64 pasmax; - pasmax = iommu->features & FEATURE_PASID_MASK; + pasmax = amd_iommu_efr & FEATURE_PASID_MASK; pasmax >>= FEATURE_PASID_SHIFT; max_pasid = (1 << (pasmax + 1)) - 1; @@ -2103,7 +2092,7 @@ static int __init iommu_init_pci(struct amd_iommu *iommu) BUG_ON(amd_iommu_max_pasid & ~PASID_MASK); - glxval = iommu->features & FEATURE_GLXVAL_MASK; + glxval = amd_iommu_efr & FEATURE_GLXVAL_MASK; glxval >>= FEATURE_GLXVAL_SHIFT; if (amd_iommu_max_glx_val == -1) @@ -2112,13 +2101,13 @@ static int __init iommu_init_pci(struct amd_iommu *iommu) amd_iommu_max_glx_val = min(amd_iommu_max_glx_val, glxval); } - if (iommu_feature(iommu, FEATURE_GT) && - iommu_feature(iommu, FEATURE_PPR)) { + if (check_feature(FEATURE_GT) && + check_feature(FEATURE_PPR)) { iommu->is_iommu_v2 = true; amd_iommu_v2_present = true; } - if (iommu_feature(iommu, FEATURE_PPR) && alloc_ppr_log(iommu)) + if (check_feature(FEATURE_PPR) && alloc_ppr_log(iommu)) return -ENOMEM; if (iommu->cap & (1UL << IOMMU_CAP_NPCACHE)) { @@ -2130,8 +2119,8 @@ static int __init iommu_init_pci(struct amd_iommu *iommu) init_iommu_perf_ctr(iommu); if (amd_iommu_pgtable == AMD_IOMMU_V2) { - if (!iommu_feature(iommu, FEATURE_GIOSUP) || - !iommu_feature(iommu, FEATURE_GT)) { + if (!check_feature(FEATURE_GIOSUP) || + !check_feature(FEATURE_GT)) { pr_warn("Cannot enable v2 page table for DMA-API. Fallback to v1.\n"); amd_iommu_pgtable = AMD_IOMMU_V1; } @@ -2181,35 +2170,29 @@ static int __init iommu_init_pci(struct amd_iommu *iommu) static void print_iommu_info(void) { + int i; static const char * const feat_str[] = { "PreF", "PPR", "X2APIC", "NX", "GT", "[5]", "IA", "GA", "HE", "PC" }; - struct amd_iommu *iommu; - - for_each_iommu(iommu) { - struct pci_dev *pdev = iommu->dev; - int i; - - pci_info(pdev, "Found IOMMU cap 0x%x\n", iommu->cap_ptr); - if (iommu->cap & (1 << IOMMU_CAP_EFR)) { - pr_info("Extended features (%#llx, %#llx):", iommu->features, iommu->features2); + if (amd_iommu_efr) { + pr_info("Extended features (%#llx, %#llx):", amd_iommu_efr, amd_iommu_efr2); - for (i = 0; i < ARRAY_SIZE(feat_str); ++i) { - if (iommu_feature(iommu, (1ULL << i))) - pr_cont(" %s", feat_str[i]); - } + for (i = 0; i < ARRAY_SIZE(feat_str); ++i) { + if (check_feature(1ULL << i)) + pr_cont(" %s", feat_str[i]); + } - if (iommu->features & FEATURE_GAM_VAPIC) - pr_cont(" GA_vAPIC"); + if (check_feature(FEATURE_GAM_VAPIC)) + pr_cont(" GA_vAPIC"); - if (iommu->features & FEATURE_SNP) - pr_cont(" SNP"); + if (check_feature(FEATURE_SNP)) + pr_cont(" SNP"); - pr_cont("\n"); - } + pr_cont("\n"); } + if (irq_remapping_enabled) { pr_info("Interrupt remapping enabled\n"); if (amd_iommu_xt_mode == IRQ_REMAP_X2APIC_MODE) @@ -2907,7 +2890,7 @@ static void enable_iommus_vapic(void) } if (AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) && - !check_feature_on_all_iommus(FEATURE_GAM_VAPIC)) { + !check_feature(FEATURE_GAM_VAPIC)) { amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY_GA; return; } @@ -3819,7 +3802,7 @@ int amd_iommu_snp_enable(void) return -EINVAL; } - amd_iommu_snp_en = check_feature_on_all_iommus(FEATURE_SNP); + amd_iommu_snp_en = check_feature(FEATURE_SNP); if (!amd_iommu_snp_en) return -EINVAL; diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 0dd8390113afa..6b9c4a9ef1509 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -1295,7 +1295,7 @@ static void amd_iommu_flush_irt_all(struct amd_iommu *iommu) void iommu_flush_all_caches(struct amd_iommu *iommu) { - if (iommu_feature(iommu, FEATURE_IA)) { + if (check_feature(FEATURE_IA)) { amd_iommu_flush_all(iommu); } else { amd_iommu_flush_dte_all(iommu); @@ -1639,7 +1639,7 @@ static void set_dte_entry(struct amd_iommu *iommu, u16 devid, flags |= DTE_FLAG_IOTLB; if (ppr) { - if (iommu_feature(iommu, FEATURE_EPHSUP)) + if (check_feature(FEATURE_EPHSUP)) pte_root |= 1ULL << DEV_ENTRY_PPR; } -- GitLab From e339b51c13ffb2173ea28679547f3abca7f4d76a Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 21 Sep 2023 09:21:42 +0000 Subject: [PATCH 0167/1451] iommu/amd: Modify logic for checking GT and PPR features In order to support v2 page table, IOMMU driver need to check if the hardware can support Guest Translation (GT) and Peripheral Page Request (PPR) features. Currently, IOMMU driver uses global (amd_iommu_v2_present) and per-iommu (struct amd_iommu.is_iommu_v2) variables to track the features. There variables area redundant since we could simply just check the global EFR mask. Therefore, replace it with a helper function with appropriate name. Signed-off-by: Suravee Suthikulpanit Co-developed-by: Vasant Hegde Signed-off-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20230921092147.5930-10-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/amd_iommu.h | 6 ++++++ drivers/iommu/amd/amd_iommu_types.h | 5 ----- drivers/iommu/amd/init.c | 9 +-------- drivers/iommu/amd/iommu.c | 2 +- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h index e1b0eeead0746..5395a21215b95 100644 --- a/drivers/iommu/amd/amd_iommu.h +++ b/drivers/iommu/amd/amd_iommu.h @@ -102,6 +102,12 @@ static inline int check_feature_gpt_level(void) return ((amd_iommu_efr >> FEATURE_GATS_SHIFT) & FEATURE_GATS_MASK); } +static inline bool amd_iommu_gt_ppr_supported(void) +{ + return (check_feature(FEATURE_GT) && + check_feature(FEATURE_PPR)); +} + static inline u64 iommu_virt_to_phys(void *vaddr) { return (u64)__sme_set(virt_to_phys(vaddr)); diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index 22bdfb0ddfb77..29e76c1e9f9e3 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -679,9 +679,6 @@ struct amd_iommu { /* Extended features 2 */ u64 features2; - /* IOMMUv2 */ - bool is_iommu_v2; - /* PCI device id of the IOMMU device */ u16 devid; @@ -890,8 +887,6 @@ extern unsigned long *amd_iommu_pd_alloc_bitmap; /* Smallest max PASID supported by any IOMMU in the system */ extern u32 amd_iommu_max_pasid; -extern bool amd_iommu_v2_present; - extern bool amd_iommu_force_isolation; /* Max levels of glxval supported */ diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index d0d506ad9cc95..06b319006ce27 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -187,7 +187,6 @@ bool amd_iommu_iotlb_sup __read_mostly = true; u32 amd_iommu_max_pasid __read_mostly = ~0; -bool amd_iommu_v2_present __read_mostly; static bool amd_iommu_pc_present __read_mostly; bool amdr_ivrs_remap_support __read_mostly; @@ -2101,12 +2100,6 @@ static int __init iommu_init_pci(struct amd_iommu *iommu) amd_iommu_max_glx_val = min(amd_iommu_max_glx_val, glxval); } - if (check_feature(FEATURE_GT) && - check_feature(FEATURE_PPR)) { - iommu->is_iommu_v2 = true; - amd_iommu_v2_present = true; - } - if (check_feature(FEATURE_PPR) && alloc_ppr_log(iommu)) return -ENOMEM; @@ -3676,7 +3669,7 @@ bool amd_iommu_v2_supported(void) * (i.e. EFR[SNPSup]=1), IOMMUv2 page table cannot be used without * setting up IOMMUv1 page table. */ - return amd_iommu_v2_present && !amd_iommu_snp_en; + return amd_iommu_gt_ppr_supported() && !amd_iommu_snp_en; } EXPORT_SYMBOL(amd_iommu_v2_supported); diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 6b9c4a9ef1509..126f58784829e 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -397,7 +397,7 @@ static int iommu_init_device(struct amd_iommu *iommu, struct device *dev) */ if ((iommu_default_passthrough() || !amd_iommu_force_isolation) && dev_is_pci(dev) && pci_iommuv2_capable(to_pci_dev(dev))) { - dev_data->iommu_v2 = iommu->is_iommu_v2; + dev_data->iommu_v2 = amd_iommu_gt_ppr_supported(); } dev_iommu_priv_set(dev, dev_data); -- GitLab From b0cc5dae1ac0c18748706a4beb636e3b726dd744 Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Thu, 21 Sep 2023 09:21:43 +0000 Subject: [PATCH 0168/1451] iommu/amd: Rename ats related variables Remove nested structure and make it as 'ats_{enable/qdep}'. Also convert 'dev_data.pri_tlp' to bit field. No functional changes intended. Signed-off-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20230921092147.5930-11-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/amd_iommu_types.h | 8 +++----- drivers/iommu/amd/iommu.c | 28 ++++++++++++++-------------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index 29e76c1e9f9e3..1c61dca638242 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -812,11 +812,9 @@ struct iommu_dev_data { struct device *dev; u16 devid; /* PCI Device ID */ bool iommu_v2; /* Device can make use of IOMMUv2 */ - struct { - bool enabled; - int qdep; - } ats; /* ATS state */ - bool pri_tlp; /* PASID TLB required for + int ats_qdep; + u8 ats_enabled :1; /* ATS state */ + u8 pri_tlp :1; /* PASID TLB required for PPR completions */ bool use_vapic; /* Enable device to use vapic mode */ bool defer_attach; diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 126f58784829e..4330002769230 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -1091,7 +1091,7 @@ static void build_inv_iotlb_pasid(struct iommu_cmd *cmd, u16 devid, u32 pasid, } static void build_complete_ppr(struct iommu_cmd *cmd, u16 devid, u32 pasid, - int status, int tag, bool gn) + int status, int tag, u8 gn) { memset(cmd, 0, sizeof(*cmd)); @@ -1314,7 +1314,7 @@ static int device_flush_iotlb(struct iommu_dev_data *dev_data, struct iommu_cmd cmd; int qdep; - qdep = dev_data->ats.qdep; + qdep = dev_data->ats_qdep; iommu = rlookup_amd_iommu(dev_data->dev); if (!iommu) return -EINVAL; @@ -1365,7 +1365,7 @@ static int device_flush_dte(struct iommu_dev_data *dev_data) return ret; } - if (dev_data->ats.enabled) + if (dev_data->ats_enabled) ret = device_flush_iotlb(dev_data, 0, ~0UL); return ret; @@ -1398,7 +1398,7 @@ static void __domain_flush_pages(struct protection_domain *domain, list_for_each_entry(dev_data, &domain->dev_list, list) { - if (!dev_data->ats.enabled) + if (!dev_data->ats_enabled) continue; ret |= device_flush_iotlb(dev_data, address, size); @@ -1718,7 +1718,7 @@ static void do_attach(struct iommu_dev_data *dev_data, iommu = rlookup_amd_iommu(dev_data->dev); if (!iommu) return; - ats = dev_data->ats.enabled; + ats = dev_data->ats_enabled; /* Update data structures */ dev_data->domain = domain; @@ -1856,14 +1856,14 @@ static int attach_device(struct device *dev, if (pdev_pri_ats_enable(pdev) != 0) goto out; - dev_data->ats.enabled = true; - dev_data->ats.qdep = pci_ats_queue_depth(pdev); + dev_data->ats_enabled = 1; + dev_data->ats_qdep = pci_ats_queue_depth(pdev); dev_data->pri_tlp = pci_prg_resp_pasid_required(pdev); } } else if (amd_iommu_iotlb_sup && pci_enable_ats(pdev, PAGE_SHIFT) == 0) { - dev_data->ats.enabled = true; - dev_data->ats.qdep = pci_ats_queue_depth(pdev); + dev_data->ats_enabled = 1; + dev_data->ats_qdep = pci_ats_queue_depth(pdev); } skip_ats_check: @@ -1920,10 +1920,10 @@ static void detach_device(struct device *dev) if (domain->flags & PD_IOMMUV2_MASK && dev_data->iommu_v2) pdev_iommuv2_disable(to_pci_dev(dev)); - else if (dev_data->ats.enabled) + else if (dev_data->ats_enabled) pci_disable_ats(to_pci_dev(dev)); - dev_data->ats.enabled = false; + dev_data->ats_enabled = 0; out: spin_unlock(&dev_data->lock); @@ -2013,7 +2013,7 @@ static void update_device_table(struct protection_domain *domain) if (!iommu) continue; set_dte_entry(iommu, dev_data->devid, domain, - dev_data->ats.enabled, dev_data->iommu_v2); + dev_data->ats_enabled, dev_data->iommu_v2); clone_aliases(iommu, dev_data->dev); } } @@ -2612,10 +2612,10 @@ static int __flush_pasid(struct protection_domain *domain, u32 pasid, There might be non-IOMMUv2 capable devices in an IOMMUv2 * domain. */ - if (!dev_data->ats.enabled) + if (!dev_data->ats_enabled) continue; - qdep = dev_data->ats.qdep; + qdep = dev_data->ats_qdep; iommu = rlookup_amd_iommu(dev_data->dev); if (!iommu) continue; -- GitLab From 739eb25514c90aa8ea053ed4d2b971f531e63ded Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 21 Sep 2023 09:21:44 +0000 Subject: [PATCH 0169/1451] iommu/amd: Introduce iommu_dev_data.ppr For AMD IOMMU, the PPR feature is needed to support IO page fault (IOPF). PPR is enabled per PCI end-point device, and is configured by the PPR bit in the IOMMU device table entry (i.e DTE[PPR]). Introducing struct iommu_dev_data.ppr track PPR setting for each device. Also iommu_dev_data.ppr will be set only when IOMMU supports PPR. Hence remove redundant feature support check in set_dte_entry(). Signed-off-by: Suravee Suthikulpanit Co-developed-by: Vasant Hegde Signed-off-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20230921092147.5930-12-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/amd_iommu_types.h | 1 + drivers/iommu/amd/iommu.c | 10 ++++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index 1c61dca638242..87fa39c490e8b 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -816,6 +816,7 @@ struct iommu_dev_data { u8 ats_enabled :1; /* ATS state */ u8 pri_tlp :1; /* PASID TLB required for PPR completions */ + u8 ppr :1; /* Enable device PPR support */ bool use_vapic; /* Enable device to use vapic mode */ bool defer_attach; diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 4330002769230..4ee69ccdc17b1 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -1638,10 +1638,8 @@ static void set_dte_entry(struct amd_iommu *iommu, u16 devid, if (ats) flags |= DTE_FLAG_IOTLB; - if (ppr) { - if (check_feature(FEATURE_EPHSUP)) - pte_root |= 1ULL << DEV_ENTRY_PPR; - } + if (ppr) + pte_root |= 1ULL << DEV_ENTRY_PPR; if (domain->flags & PD_IOMMUV2_MASK) { u64 gcr3 = iommu_virt_to_phys(domain->gcr3_tbl); @@ -1734,7 +1732,7 @@ static void do_attach(struct iommu_dev_data *dev_data, /* Update device table */ set_dte_entry(iommu, dev_data->devid, domain, - ats, dev_data->iommu_v2); + ats, dev_data->ppr); clone_aliases(iommu, dev_data->dev); device_flush_dte(dev_data); @@ -2013,7 +2011,7 @@ static void update_device_table(struct protection_domain *domain) if (!iommu) continue; set_dte_entry(iommu, dev_data->devid, domain, - dev_data->ats_enabled, dev_data->iommu_v2); + dev_data->ats_enabled, dev_data->ppr); clone_aliases(iommu, dev_data->dev); } } -- GitLab From 92e2bd56a5f9fc44313fda802a43a63cc2a9c8f6 Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Thu, 21 Sep 2023 09:21:45 +0000 Subject: [PATCH 0170/1451] iommu/amd: Introduce iommu_dev_data.flags to track device capabilities Currently we use struct iommu_dev_data.iommu_v2 to keep track of the device ATS, PRI, and PASID capabilities. But these capabilities can be enabled independently (except PRI requires ATS support). Hence, replace the iommu_v2 variable with a flags variable, which keep track of the device capabilities. From commit 9bf49e36d718 ("PCI/ATS: Handle sharing of PF PRI Capability with all VFs"), device PRI/PASID is shared between PF and any associated VFs. Hence use pci_pri_supported() and pci_pasid_features() instead of pci_find_ext_capability() to check device PRI/PASID support. Signed-off-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20230921092147.5930-13-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/amd_iommu_types.h | 3 +- drivers/iommu/amd/iommu.c | 46 ++++++++++++++++++----------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index 87fa39c490e8b..07f8919ee34e6 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -811,7 +811,8 @@ struct iommu_dev_data { struct protection_domain *domain; /* Domain the device is bound to */ struct device *dev; u16 devid; /* PCI Device ID */ - bool iommu_v2; /* Device can make use of IOMMUv2 */ + + u32 flags; /* Holds AMD_IOMMU_DEVICE_FLAG_<*> */ int ats_qdep; u8 ats_enabled :1; /* ATS state */ u8 pri_tlp :1; /* PASID TLB required for diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 4ee69ccdc17b1..151f405686e3e 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -319,24 +319,34 @@ static struct iommu_group *acpihid_device_group(struct device *dev) return entry->group; } -static bool pci_iommuv2_capable(struct pci_dev *pdev) +static inline bool pdev_pasid_supported(struct iommu_dev_data *dev_data) { - static const int caps[] = { - PCI_EXT_CAP_ID_PRI, - PCI_EXT_CAP_ID_PASID, - }; - int i, pos; + return (dev_data->flags & AMD_IOMMU_DEVICE_FLAG_PASID_SUP); +} - if (!pci_ats_supported(pdev)) - return false; +static u32 pdev_get_caps(struct pci_dev *pdev) +{ + int features; + u32 flags = 0; + + if (pci_ats_supported(pdev)) + flags |= AMD_IOMMU_DEVICE_FLAG_ATS_SUP; + + if (pci_pri_supported(pdev)) + flags |= AMD_IOMMU_DEVICE_FLAG_PRI_SUP; - for (i = 0; i < 2; ++i) { - pos = pci_find_ext_capability(pdev, caps[i]); - if (pos == 0) - return false; + features = pci_pasid_features(pdev); + if (features >= 0) { + flags |= AMD_IOMMU_DEVICE_FLAG_PASID_SUP; + + if (features & PCI_PASID_CAP_EXEC) + flags |= AMD_IOMMU_DEVICE_FLAG_EXEC_SUP; + + if (features & PCI_PASID_CAP_PRIV) + flags |= AMD_IOMMU_DEVICE_FLAG_PRIV_SUP; } - return true; + return flags; } /* @@ -396,8 +406,8 @@ static int iommu_init_device(struct amd_iommu *iommu, struct device *dev) * it'll be forced to go into translation mode. */ if ((iommu_default_passthrough() || !amd_iommu_force_isolation) && - dev_is_pci(dev) && pci_iommuv2_capable(to_pci_dev(dev))) { - dev_data->iommu_v2 = amd_iommu_gt_ppr_supported(); + dev_is_pci(dev) && amd_iommu_gt_ppr_supported()) { + dev_data->flags = pdev_get_caps(to_pci_dev(dev)); } dev_iommu_priv_set(dev, dev_data); @@ -1850,7 +1860,7 @@ static int attach_device(struct device *dev, goto out; } - if (dev_data->iommu_v2) { + if (pdev_pasid_supported(dev_data)) { if (pdev_pri_ats_enable(pdev) != 0) goto out; @@ -1916,7 +1926,7 @@ static void detach_device(struct device *dev) if (!dev_is_pci(dev)) goto out; - if (domain->flags & PD_IOMMUV2_MASK && dev_data->iommu_v2) + if (domain->flags & PD_IOMMUV2_MASK && pdev_pasid_supported(dev_data)) pdev_iommuv2_disable(to_pci_dev(dev)); else if (dev_data->ats_enabled) pci_disable_ats(to_pci_dev(dev)); @@ -2471,7 +2481,7 @@ static int amd_iommu_def_domain_type(struct device *dev) * and require remapping. * - SNP is enabled, because it prohibits DTE[Mode]=0. */ - if (dev_data->iommu_v2 && + if (pdev_pasid_supported(dev_data) && !cc_platform_has(CC_ATTR_MEM_ENCRYPT) && !amd_iommu_snp_en) { return IOMMU_DOMAIN_IDENTITY; -- GitLab From eda8c2860ab6799620c6fbb8600d56e32f437a90 Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Thu, 21 Sep 2023 09:21:46 +0000 Subject: [PATCH 0171/1451] iommu/amd: Enable device ATS/PASID/PRI capabilities independently Introduce helper functions to enable/disable device ATS/PASID/PRI capabilities independently along with the new pasid_enabled and pri_enabled variables in struct iommu_dev_data to keep track, which allows attach_device() and detach_device() to be simplified. Co-developed-by: Suravee Suthikulpanit Signed-off-by: Suravee Suthikulpanit Signed-off-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20230921092147.5930-14-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/amd_iommu.h | 4 + drivers/iommu/amd/amd_iommu_types.h | 2 + drivers/iommu/amd/iommu.c | 203 ++++++++++++++++------------ 3 files changed, 120 insertions(+), 89 deletions(-) diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h index 5395a21215b95..9df53961d5ef1 100644 --- a/drivers/iommu/amd/amd_iommu.h +++ b/drivers/iommu/amd/amd_iommu.h @@ -51,6 +51,10 @@ int amd_iommu_pc_get_reg(struct amd_iommu *iommu, u8 bank, u8 cntr, int amd_iommu_pc_set_reg(struct amd_iommu *iommu, u8 bank, u8 cntr, u8 fxn, u64 *value); +/* Device capabilities */ +int amd_iommu_pdev_enable_cap_pri(struct pci_dev *pdev); +void amd_iommu_pdev_disable_cap_pri(struct pci_dev *pdev); + int amd_iommu_register_ppr_notifier(struct notifier_block *nb); int amd_iommu_unregister_ppr_notifier(struct notifier_block *nb); void amd_iommu_domain_direct_map(struct iommu_domain *dom); diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index 07f8919ee34e6..c6d47cb7a0eeb 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -815,6 +815,8 @@ struct iommu_dev_data { u32 flags; /* Holds AMD_IOMMU_DEVICE_FLAG_<*> */ int ats_qdep; u8 ats_enabled :1; /* ATS state */ + u8 pri_enabled :1; /* PRI state */ + u8 pasid_enabled:1; /* PASID state */ u8 pri_tlp :1; /* PASID TLB required for PPR completions */ u8 ppr :1; /* Enable device PPR support */ diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 151f405686e3e..f3448a2b6c0ee 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -349,6 +349,113 @@ static u32 pdev_get_caps(struct pci_dev *pdev) return flags; } +static inline int pdev_enable_cap_ats(struct pci_dev *pdev) +{ + struct iommu_dev_data *dev_data = dev_iommu_priv_get(&pdev->dev); + int ret = -EINVAL; + + if (dev_data->ats_enabled) + return 0; + + if (amd_iommu_iotlb_sup && + (dev_data->flags & AMD_IOMMU_DEVICE_FLAG_ATS_SUP)) { + ret = pci_enable_ats(pdev, PAGE_SHIFT); + if (!ret) { + dev_data->ats_enabled = 1; + dev_data->ats_qdep = pci_ats_queue_depth(pdev); + } + } + + return ret; +} + +static inline void pdev_disable_cap_ats(struct pci_dev *pdev) +{ + struct iommu_dev_data *dev_data = dev_iommu_priv_get(&pdev->dev); + + if (dev_data->ats_enabled) { + pci_disable_ats(pdev); + dev_data->ats_enabled = 0; + } +} + +int amd_iommu_pdev_enable_cap_pri(struct pci_dev *pdev) +{ + struct iommu_dev_data *dev_data = dev_iommu_priv_get(&pdev->dev); + int ret = -EINVAL; + + if (dev_data->pri_enabled) + return 0; + + if (dev_data->flags & AMD_IOMMU_DEVICE_FLAG_PRI_SUP) { + /* + * First reset the PRI state of the device. + * FIXME: Hardcode number of outstanding requests for now + */ + if (!pci_reset_pri(pdev) && !pci_enable_pri(pdev, 32)) { + dev_data->pri_enabled = 1; + dev_data->pri_tlp = pci_prg_resp_pasid_required(pdev); + + ret = 0; + } + } + + return ret; +} + +void amd_iommu_pdev_disable_cap_pri(struct pci_dev *pdev) +{ + struct iommu_dev_data *dev_data = dev_iommu_priv_get(&pdev->dev); + + if (dev_data->pri_enabled) { + pci_disable_pri(pdev); + dev_data->pri_enabled = 0; + } +} + +static inline int pdev_enable_cap_pasid(struct pci_dev *pdev) +{ + struct iommu_dev_data *dev_data = dev_iommu_priv_get(&pdev->dev); + int ret = -EINVAL; + + if (dev_data->pasid_enabled) + return 0; + + if (dev_data->flags & AMD_IOMMU_DEVICE_FLAG_PASID_SUP) { + /* Only allow access to user-accessible pages */ + ret = pci_enable_pasid(pdev, 0); + if (!ret) + dev_data->pasid_enabled = 1; + } + + return ret; +} + +static inline void pdev_disable_cap_pasid(struct pci_dev *pdev) +{ + struct iommu_dev_data *dev_data = dev_iommu_priv_get(&pdev->dev); + + if (dev_data->pasid_enabled) { + pci_disable_pasid(pdev); + dev_data->pasid_enabled = 0; + } +} + +static void pdev_enable_caps(struct pci_dev *pdev) +{ + pdev_enable_cap_ats(pdev); + pdev_enable_cap_pasid(pdev); + amd_iommu_pdev_enable_cap_pri(pdev); + +} + +static void pdev_disable_caps(struct pci_dev *pdev) +{ + pdev_disable_cap_ats(pdev); + pdev_disable_cap_pasid(pdev); + amd_iommu_pdev_disable_cap_pri(pdev); +} + /* * This function checks if the driver got a valid device from the caller to * avoid dereferencing invalid pointers. @@ -1777,48 +1884,6 @@ static void do_detach(struct iommu_dev_data *dev_data) domain->dev_cnt -= 1; } -static void pdev_iommuv2_disable(struct pci_dev *pdev) -{ - pci_disable_ats(pdev); - pci_disable_pri(pdev); - pci_disable_pasid(pdev); -} - -static int pdev_pri_ats_enable(struct pci_dev *pdev) -{ - int ret; - - /* Only allow access to user-accessible pages */ - ret = pci_enable_pasid(pdev, 0); - if (ret) - return ret; - - /* First reset the PRI state of the device */ - ret = pci_reset_pri(pdev); - if (ret) - goto out_err_pasid; - - /* Enable PRI */ - /* FIXME: Hardcode number of outstanding requests for now */ - ret = pci_enable_pri(pdev, 32); - if (ret) - goto out_err_pasid; - - ret = pci_enable_ats(pdev, PAGE_SHIFT); - if (ret) - goto out_err_pri; - - return 0; - -out_err_pri: - pci_disable_pri(pdev); - -out_err_pasid: - pci_disable_pasid(pdev); - - return ret; -} - /* * If a device is not yet associated with a domain, this function makes the * device visible in the domain @@ -1827,9 +1892,8 @@ static int attach_device(struct device *dev, struct protection_domain *domain) { struct iommu_dev_data *dev_data; - struct pci_dev *pdev; unsigned long flags; - int ret; + int ret = 0; spin_lock_irqsave(&domain->lock, flags); @@ -1837,45 +1901,13 @@ static int attach_device(struct device *dev, spin_lock(&dev_data->lock); - ret = -EBUSY; - if (dev_data->domain != NULL) + if (dev_data->domain != NULL) { + ret = -EBUSY; goto out; - - if (!dev_is_pci(dev)) - goto skip_ats_check; - - pdev = to_pci_dev(dev); - if (domain->flags & PD_IOMMUV2_MASK) { - struct iommu_domain *def_domain = iommu_get_dma_domain(dev); - - ret = -EINVAL; - - /* - * In case of using AMD_IOMMU_V1 page table mode and the device - * is enabling for PPR/ATS support (using v2 table), - * we need to make sure that the domain type is identity map. - */ - if ((amd_iommu_pgtable == AMD_IOMMU_V1) && - def_domain->type != IOMMU_DOMAIN_IDENTITY) { - goto out; - } - - if (pdev_pasid_supported(dev_data)) { - if (pdev_pri_ats_enable(pdev) != 0) - goto out; - - dev_data->ats_enabled = 1; - dev_data->ats_qdep = pci_ats_queue_depth(pdev); - dev_data->pri_tlp = pci_prg_resp_pasid_required(pdev); - } - } else if (amd_iommu_iotlb_sup && - pci_enable_ats(pdev, PAGE_SHIFT) == 0) { - dev_data->ats_enabled = 1; - dev_data->ats_qdep = pci_ats_queue_depth(pdev); } -skip_ats_check: - ret = 0; + if (dev_is_pci(dev)) + pdev_enable_caps(to_pci_dev(dev)); do_attach(dev_data, domain); @@ -1923,15 +1955,8 @@ static void detach_device(struct device *dev) do_detach(dev_data); - if (!dev_is_pci(dev)) - goto out; - - if (domain->flags & PD_IOMMUV2_MASK && pdev_pasid_supported(dev_data)) - pdev_iommuv2_disable(to_pci_dev(dev)); - else if (dev_data->ats_enabled) - pci_disable_ats(to_pci_dev(dev)); - - dev_data->ats_enabled = 0; + if (dev_is_pci(dev)) + pdev_disable_caps(to_pci_dev(dev)); out: spin_unlock(&dev_data->lock); -- GitLab From 7016b3005547bae3ba4577980db0ede53a79784a Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Thu, 21 Sep 2023 09:21:47 +0000 Subject: [PATCH 0172/1451] iommu/amd: Initialize iommu_device->max_pasids Commit 1adf3cc20d69 ("iommu: Add max_pasids field in struct iommu_device") introduced a variable struct iommu_device.max_pasids to track max PASIDS supported by each IOMMU. Let us initialize this field for AMD IOMMU. IOMMU core will use this value to set max PASIDs per device (see __iommu_probe_device()). Also remove unused global 'amd_iommu_max_pasid' variable. Signed-off-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20230921092147.5930-15-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/amd_iommu_types.h | 3 --- drivers/iommu/amd/init.c | 9 ++------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index c6d47cb7a0eeb..5be563d55ad64 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -886,9 +886,6 @@ extern unsigned amd_iommu_aperture_order; /* allocation bitmap for domain ids */ extern unsigned long *amd_iommu_pd_alloc_bitmap; -/* Smallest max PASID supported by any IOMMU in the system */ -extern u32 amd_iommu_max_pasid; - extern bool amd_iommu_force_isolation; /* Max levels of glxval supported */ diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index 06b319006ce27..463e68a88b174 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -185,8 +185,6 @@ static int amd_iommus_present; bool amd_iommu_np_cache __read_mostly; bool amd_iommu_iotlb_sup __read_mostly = true; -u32 amd_iommu_max_pasid __read_mostly = ~0; - static bool amd_iommu_pc_present __read_mostly; bool amdr_ivrs_remap_support __read_mostly; @@ -2080,16 +2078,13 @@ static int __init iommu_init_pci(struct amd_iommu *iommu) if (check_feature(FEATURE_GT)) { int glxval; - u32 max_pasid; u64 pasmax; pasmax = amd_iommu_efr & FEATURE_PASID_MASK; pasmax >>= FEATURE_PASID_SHIFT; - max_pasid = (1 << (pasmax + 1)) - 1; - - amd_iommu_max_pasid = min(amd_iommu_max_pasid, max_pasid); + iommu->iommu.max_pasids = (1 << (pasmax + 1)) - 1; - BUG_ON(amd_iommu_max_pasid & ~PASID_MASK); + BUG_ON(iommu->iommu.max_pasids & ~PASID_MASK); glxval = amd_iommu_efr & FEATURE_GLXVAL_MASK; glxval >>= FEATURE_GLXVAL_SHIFT; -- GitLab From ccb76c5751634541bfd2222374f46e1dea83d525 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Fri, 18 Aug 2023 17:26:20 +0800 Subject: [PATCH 0173/1451] iommu: Remove duplicate include ./drivers/iommu/iommu.c: iommu-priv.h is included more than once. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=6186 Signed-off-by: Jiapeng Chong Link: https://lore.kernel.org/r/20230818092620.91748-1-jiapeng.chong@linux.alibaba.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index b2d08e422942b..1ecac2b5c54f4 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -37,7 +37,6 @@ #include "iommu-priv.h" #include "iommu-sva.h" -#include "iommu-priv.h" static struct kset *iommu_group_kset; static DEFINE_IDA(iommu_group_ida); -- GitLab From f7da9c081517daba70f9f9342e09d7a6322ba323 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Fri, 1 Sep 2023 15:30:56 +0800 Subject: [PATCH 0174/1451] iommu/tegra-smmu: Drop unnecessary error check for for debugfs_create_dir() The debugfs_create_dir() function returns error pointers. It never returns NULL. As Baolu suggested, this patch removes the error checking for debugfs_create_dir in tegra-smmu.c. This is because the DebugFS kernel API is developed in a way that the caller can safely ignore the errors that occur during the creation of DebugFS nodes. The debugfs APIs have a IS_ERR() judge in start_creating() which can handle it gracefully. So these checks are unnecessary. Fixes: d1313e7896e9 ("iommu/tegra-smmu: Add debugfs support") Signed-off-by: Jinjie Ruan Suggested-by: Baolu Lu Acked-by: Thierry Reding Reviewed-by: Jason Gunthorpe Link: https://lore.kernel.org/r/20230901073056.1364755-1-ruanjinjie@huawei.com Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-smmu.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index e445f80d02263..0060609c0673d 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -1056,8 +1056,6 @@ DEFINE_SHOW_ATTRIBUTE(tegra_smmu_clients); static void tegra_smmu_debugfs_init(struct tegra_smmu *smmu) { smmu->debugfs = debugfs_create_dir("smmu", NULL); - if (!smmu->debugfs) - return; debugfs_create_file("swgroups", S_IRUGO, smmu->debugfs, smmu, &tegra_smmu_swgroups_fops); -- GitLab From 7405116519ad70b8c7340359bfac8db8279e7ce4 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Wed, 30 Aug 2023 16:16:06 +0100 Subject: [PATCH 0175/1451] media: qcom: camss: Fix pm_domain_on sequence in probe We need to make sure camss_configure_pd() happens before camss_register_entities() as the vfe_get() path relies on the pointer provided by camss_configure_pd(). Fix the ordering sequence in probe to ensure the pointers vfe_get() demands are present by the time camss_register_entities() runs. In order to facilitate backporting to stable kernels I've moved the configure_pd() call pretty early on the probe() function so that irrespective of the existence of the old error handling jump labels this patch should still apply to -next circa Aug 2023 to v5.13 inclusive. Fixes: 2f6f8af67203 ("media: camss: Refactor VFE power domain toggling") Cc: stable@vger.kernel.org Signed-off-by: Bryan O'Donoghue Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index f11dc59135a5a..75991d849b571 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -1619,6 +1619,12 @@ static int camss_probe(struct platform_device *pdev) if (ret < 0) goto err_cleanup; + ret = camss_configure_pd(camss); + if (ret < 0) { + dev_err(dev, "Failed to configure power domains: %d\n", ret); + goto err_cleanup; + } + ret = camss_init_subdevices(camss); if (ret < 0) goto err_cleanup; @@ -1678,12 +1684,6 @@ static int camss_probe(struct platform_device *pdev) } } - ret = camss_configure_pd(camss); - if (ret < 0) { - dev_err(dev, "Failed to configure power domains: %d\n", ret); - return ret; - } - pm_runtime_enable(dev); return 0; -- GitLab From b278080a89f452063915beda0ade6b3ed5ee4271 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Wed, 30 Aug 2023 16:16:07 +0100 Subject: [PATCH 0176/1451] media: qcom: camss: Fix V4L2 async notifier error path Previously the jump label err_cleanup was used higher in the probe() function to release the async notifier however the async notifier registration was moved later in the code rendering the previous four jumps redundant. Rename the label from err_cleanup to err_v4l2_device_unregister to capture what the jump does. Fixes: 51397a4ec75d ("media: qcom: Initialise V4L2 async notifier later") Signed-off-by: Bryan O'Donoghue Signed-off-by: Hans Verkuil [hverkuil: fix old name in commit log: err_v4l2_device_register -> err_v4l2_device_unregister] --- drivers/media/platform/qcom/camss/camss.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 75991d849b571..a925b2bfd8989 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -1617,21 +1617,21 @@ static int camss_probe(struct platform_device *pdev) ret = camss_icc_get(camss); if (ret < 0) - goto err_cleanup; + return ret; ret = camss_configure_pd(camss); if (ret < 0) { dev_err(dev, "Failed to configure power domains: %d\n", ret); - goto err_cleanup; + return ret; } ret = camss_init_subdevices(camss); if (ret < 0) - goto err_cleanup; + return ret; ret = dma_set_mask_and_coherent(dev, 0xffffffff); if (ret) - goto err_cleanup; + return ret; camss->media_dev.dev = camss->dev; strscpy(camss->media_dev.model, "Qualcomm Camera Subsystem", @@ -1643,7 +1643,7 @@ static int camss_probe(struct platform_device *pdev) ret = v4l2_device_register(camss->dev, &camss->v4l2_dev); if (ret < 0) { dev_err(dev, "Failed to register V4L2 device: %d\n", ret); - goto err_cleanup; + return ret; } v4l2_async_nf_init(&camss->notifier, &camss->v4l2_dev); @@ -1651,12 +1651,12 @@ static int camss_probe(struct platform_device *pdev) num_subdevs = camss_of_parse_ports(camss); if (num_subdevs < 0) { ret = num_subdevs; - goto err_cleanup; + goto err_v4l2_device_unregister; } ret = camss_register_entities(camss); if (ret < 0) - goto err_cleanup; + goto err_v4l2_device_unregister; if (num_subdevs) { camss->notifier.ops = &camss_subdev_notifier_ops; @@ -1690,7 +1690,7 @@ static int camss_probe(struct platform_device *pdev) err_register_subdevs: camss_unregister_entities(camss); -err_cleanup: +err_v4l2_device_unregister: v4l2_device_unregister(&camss->v4l2_dev); v4l2_async_nf_cleanup(&camss->notifier); -- GitLab From f69791c39745e64621216fe8919cb73c0065002b Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Wed, 30 Aug 2023 16:16:08 +0100 Subject: [PATCH 0177/1451] media: qcom: camss: Fix genpd cleanup Right now we never release the power-domains properly on the error path. Add a routine to be reused for this purpose and appropriate jumps in probe() to run that routine where necessary. Fixes: 2f6f8af67203 ("media: camss: Refactor VFE power domain toggling") Cc: stable@vger.kernel.org Signed-off-by: Bryan O'Donoghue Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss.c | 35 ++++++++++++++--------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index a925b2bfd8989..c6df862c79e39 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -1538,6 +1538,20 @@ static int camss_icc_get(struct camss *camss) return 0; } +static void camss_genpd_cleanup(struct camss *camss) +{ + int i; + + if (camss->genpd_num == 1) + return; + + if (camss->genpd_num > camss->vfe_num) + device_link_del(camss->genpd_link[camss->genpd_num - 1]); + + for (i = 0; i < camss->genpd_num; i++) + dev_pm_domain_detach(camss->genpd[i], true); +} + /* * camss_probe - Probe CAMSS platform device * @pdev: Pointer to CAMSS platform device @@ -1627,11 +1641,11 @@ static int camss_probe(struct platform_device *pdev) ret = camss_init_subdevices(camss); if (ret < 0) - return ret; + goto err_genpd_cleanup; ret = dma_set_mask_and_coherent(dev, 0xffffffff); if (ret) - return ret; + goto err_genpd_cleanup; camss->media_dev.dev = camss->dev; strscpy(camss->media_dev.model, "Qualcomm Camera Subsystem", @@ -1643,7 +1657,7 @@ static int camss_probe(struct platform_device *pdev) ret = v4l2_device_register(camss->dev, &camss->v4l2_dev); if (ret < 0) { dev_err(dev, "Failed to register V4L2 device: %d\n", ret); - return ret; + goto err_genpd_cleanup; } v4l2_async_nf_init(&camss->notifier, &camss->v4l2_dev); @@ -1693,28 +1707,19 @@ static int camss_probe(struct platform_device *pdev) err_v4l2_device_unregister: v4l2_device_unregister(&camss->v4l2_dev); v4l2_async_nf_cleanup(&camss->notifier); +err_genpd_cleanup: + camss_genpd_cleanup(camss); return ret; } void camss_delete(struct camss *camss) { - int i; - v4l2_device_unregister(&camss->v4l2_dev); media_device_unregister(&camss->media_dev); media_device_cleanup(&camss->media_dev); pm_runtime_disable(camss->dev); - - if (camss->genpd_num == 1) - return; - - if (camss->genpd_num > camss->vfe_num) - device_link_del(camss->genpd_link[camss->genpd_num - 1]); - - for (i = 0; i < camss->genpd_num; i++) - dev_pm_domain_detach(camss->genpd[i], true); } /* @@ -1733,6 +1738,8 @@ static void camss_remove(struct platform_device *pdev) if (atomic_read(&camss->ref_count) == 0) camss_delete(camss); + + camss_genpd_cleanup(camss); } static const struct of_device_id camss_dt_match[] = { -- GitLab From 26bda3da00c3edef727a6acb00ed2eb4b22f8723 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Wed, 30 Aug 2023 16:16:09 +0100 Subject: [PATCH 0178/1451] media: qcom: camss: Fix vfe_get() error jump Right now it is possible to do a vfe_get() with the internal reference count at 1. If vfe_check_clock_rates() returns non-zero then we will leave the reference count as-is and run: - pm_runtime_put_sync() - vfe->ops->pm_domain_off() skip: - camss_disable_clocks() Subsequent vfe_put() calls will when the ref-count is non-zero unconditionally run: - pm_runtime_put_sync() - vfe->ops->pm_domain_off() - camss_disable_clocks() vfe_get() should not attempt to roll-back on error when the ref-count is non-zero as the upper layers will still do their own vfe_put() operations. vfe_put() will drop the reference count and do the necessary power domain release, the cleanup jumps in vfe_get() should only be run when the ref-count is zero. [ 50.095796] CPU: 7 PID: 3075 Comm: cam Not tainted 6.3.2+ #80 [ 50.095798] Hardware name: LENOVO 21BXCTO1WW/21BXCTO1WW, BIOS N3HET82W (1.54 ) 05/26/2023 [ 50.095799] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 50.095802] pc : refcount_warn_saturate+0xf4/0x148 [ 50.095804] lr : refcount_warn_saturate+0xf4/0x148 [ 50.095805] sp : ffff80000c7cb8b0 [ 50.095806] x29: ffff80000c7cb8b0 x28: ffff16ecc0e3fc10 x27: 0000000000000000 [ 50.095810] x26: 0000000000000000 x25: 0000000000020802 x24: 0000000000000000 [ 50.095813] x23: ffff16ecc7360640 x22: 00000000ffffffff x21: 0000000000000005 [ 50.095815] x20: ffff16ed175f4400 x19: ffffb4d9852942a8 x18: ffffffffffffffff [ 50.095818] x17: ffffb4d9852d4a48 x16: ffffb4d983da5db8 x15: ffff80000c7cb320 [ 50.095821] x14: 0000000000000001 x13: 2e656572662d7265 x12: 7466612d65737520 [ 50.095823] x11: 00000000ffffefff x10: ffffb4d9850cebf0 x9 : ffffb4d9835cf954 [ 50.095826] x8 : 0000000000017fe8 x7 : c0000000ffffefff x6 : 0000000000057fa8 [ 50.095829] x5 : ffff16f813fe3d08 x4 : 0000000000000000 x3 : ffff621e8f4d2000 [ 50.095832] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff16ed32119040 [ 50.095835] Call trace: [ 50.095836] refcount_warn_saturate+0xf4/0x148 [ 50.095838] device_link_put_kref+0x84/0xc8 [ 50.095843] device_link_del+0x38/0x58 [ 50.095846] vfe_pm_domain_off+0x3c/0x50 [qcom_camss] [ 50.095860] vfe_put+0x114/0x140 [qcom_camss] [ 50.095869] csid_set_power+0x2c8/0x408 [qcom_camss] [ 50.095878] pipeline_pm_power_one+0x164/0x170 [videodev] [ 50.095896] pipeline_pm_power+0xc4/0x110 [videodev] [ 50.095909] v4l2_pipeline_pm_use+0x5c/0xa0 [videodev] [ 50.095923] v4l2_pipeline_pm_get+0x1c/0x30 [videodev] [ 50.095937] video_open+0x7c/0x100 [qcom_camss] [ 50.095945] v4l2_open+0x84/0x130 [videodev] [ 50.095960] chrdev_open+0xc8/0x250 [ 50.095964] do_dentry_open+0x1bc/0x498 [ 50.095966] vfs_open+0x34/0x40 [ 50.095968] path_openat+0xb44/0xf20 [ 50.095971] do_filp_open+0xa4/0x160 [ 50.095974] do_sys_openat2+0xc8/0x188 [ 50.095975] __arm64_sys_openat+0x6c/0xb8 [ 50.095977] invoke_syscall+0x50/0x128 [ 50.095982] el0_svc_common.constprop.0+0x4c/0x100 [ 50.095985] do_el0_svc+0x40/0xa8 [ 50.095988] el0_svc+0x2c/0x88 [ 50.095991] el0t_64_sync_handler+0xf4/0x120 [ 50.095994] el0t_64_sync+0x190/0x198 [ 50.095996] ---[ end trace 0000000000000000 ]--- Fixes: 779096916dae ("media: camss: vfe: Fix runtime PM imbalance on error") Cc: stable@vger.kernel.org Signed-off-by: Bryan O'Donoghue Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss-vfe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 06c95568e5af4..5d8462ec0af29 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -611,7 +611,7 @@ int vfe_get(struct vfe_device *vfe) } else { ret = vfe_check_clock_rates(vfe); if (ret < 0) - goto error_pm_runtime_get; + goto error_pm_domain; } vfe->power_count++; -- GitLab From 3143ad282fc08bf995ee73e32a9e40c527bf265d Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Wed, 30 Aug 2023 16:16:10 +0100 Subject: [PATCH 0179/1451] media: qcom: camss: Fix VFE-17x vfe_disable_output() There are two problems with the current vfe_disable_output() routine. Firstly we rightly use a spinlock to protect output->gen2.active_num everywhere except for in the IDLE timeout path of vfe_disable_output(). Even if that is not racy "in practice" somehow it is by happenstance not by design. Secondly we do not get consistent behaviour from this routine. On sc8280xp 50% of the time I get "VFE idle timeout - resetting". In this case the subsequent capture will succeed. The other 50% of the time, we don't hit the idle timeout, never do the VFE reset and subsequent captures stall indefinitely. Rewrite the vfe_disable_output() routine to - Quiesce write masters with vfe_wm_stop() - Set active_num = 0 remembering to hold the spinlock when we do so followed by - Reset the VFE Testing on sc8280xp and sdm845 shows this to be a valid fix. Fixes: 7319cdf189bb ("media: camss: Add support for VFE hardware version Titan 170") Cc: stable@vger.kernel.org Signed-off-by: Bryan O'Donoghue Signed-off-by: Hans Verkuil --- .../media/platform/qcom/camss/camss-vfe-170.c | 22 +++---------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c index 02494c89da91c..168baaa80d4e6 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-170.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c @@ -7,7 +7,6 @@ * Copyright (C) 2020-2021 Linaro Ltd. */ -#include #include #include #include @@ -494,35 +493,20 @@ static int vfe_enable_output(struct vfe_line *line) return 0; } -static int vfe_disable_output(struct vfe_line *line) +static void vfe_disable_output(struct vfe_line *line) { struct vfe_device *vfe = to_vfe(line); struct vfe_output *output = &line->output; unsigned long flags; unsigned int i; - bool done; - int timeout = 0; - - do { - spin_lock_irqsave(&vfe->output_lock, flags); - done = !output->gen2.active_num; - spin_unlock_irqrestore(&vfe->output_lock, flags); - usleep_range(10000, 20000); - - if (timeout++ == 100) { - dev_err(vfe->camss->dev, "VFE idle timeout - resetting\n"); - vfe_reset(vfe); - output->gen2.active_num = 0; - return 0; - } - } while (!done); spin_lock_irqsave(&vfe->output_lock, flags); for (i = 0; i < output->wm_num; i++) vfe_wm_stop(vfe, output->wm_idx[i]); + output->gen2.active_num = 0; spin_unlock_irqrestore(&vfe->output_lock, flags); - return 0; + vfe_reset(vfe); } /* -- GitLab From 7f24d291350426d40b36dfbe6b3090617cdfd37a Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Wed, 30 Aug 2023 16:16:11 +0100 Subject: [PATCH 0180/1451] media: qcom: camss: Fix VFE-480 vfe_disable_output() vfe-480 is copied from vfe-17x and has the same racy idle timeout bug as in 17x. Fix the vfe_disable_output() logic to no longer be racy and to conform to the 17x way of quiescing and then resetting the VFE. Fixes: 4edc8eae715c ("media: camss: Add initial support for VFE hardware version Titan 480") Cc: stable@vger.kernel.org Signed-off-by: Bryan O'Donoghue Signed-off-by: Hans Verkuil --- .../media/platform/qcom/camss/camss-vfe-480.c | 22 +++---------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-480.c b/drivers/media/platform/qcom/camss/camss-vfe-480.c index f70aad2e8c237..8ddb8016434ae 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-480.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-480.c @@ -8,7 +8,6 @@ * Copyright (C) 2021 Jonathan Marek */ -#include #include #include #include @@ -328,35 +327,20 @@ static int vfe_enable_output(struct vfe_line *line) return 0; } -static int vfe_disable_output(struct vfe_line *line) +static void vfe_disable_output(struct vfe_line *line) { struct vfe_device *vfe = to_vfe(line); struct vfe_output *output = &line->output; unsigned long flags; unsigned int i; - bool done; - int timeout = 0; - - do { - spin_lock_irqsave(&vfe->output_lock, flags); - done = !output->gen2.active_num; - spin_unlock_irqrestore(&vfe->output_lock, flags); - usleep_range(10000, 20000); - - if (timeout++ == 100) { - dev_err(vfe->camss->dev, "VFE idle timeout - resetting\n"); - vfe_reset(vfe); - output->gen2.active_num = 0; - return 0; - } - } while (!done); spin_lock_irqsave(&vfe->output_lock, flags); for (i = 0; i < output->wm_num; i++) vfe_wm_stop(vfe, output->wm_idx[i]); + output->gen2.active_num = 0; spin_unlock_irqrestore(&vfe->output_lock, flags); - return 0; + vfe_reset(vfe); } /* -- GitLab From b6e1bdca463a932c1ac02caa7d3e14bf39288e0c Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Wed, 30 Aug 2023 16:16:12 +0100 Subject: [PATCH 0181/1451] media: qcom: camss: Fix missing vfe_lite clocks check check_clock doesn't account for vfe_lite which means that vfe_lite will never get validated by this routine. Add the clock name to the expected set to remediate. Fixes: 7319cdf189bb ("media: camss: Add support for VFE hardware version Titan 170") Cc: stable@vger.kernel.org Signed-off-by: Bryan O'Donoghue Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss-vfe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 5d8462ec0af29..965500b83d073 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -535,7 +535,8 @@ static int vfe_check_clock_rates(struct vfe_device *vfe) struct camss_clock *clock = &vfe->clock[i]; if (!strcmp(clock->name, "vfe0") || - !strcmp(clock->name, "vfe1")) { + !strcmp(clock->name, "vfe1") || + !strcmp(clock->name, "vfe_lite")) { u64 min_rate = 0; unsigned long rate; -- GitLab From d8f7e1a60d01739a1d78db2b08603089c6cf7c8e Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Wed, 30 Aug 2023 16:16:13 +0100 Subject: [PATCH 0182/1451] media: qcom: camss: Fix invalid clock enable bit disjunction define CSIPHY_3PH_CMN_CSI_COMMON_CTRL5_CLK_ENABLE BIT(7) disjunction for gen2 ? BIT(7) : is a nop we are setting the same bit either way. Fixes: 4abb21309fda ("media: camss: csiphy: Move to hardcode CSI Clock Lane number") Cc: stable@vger.kernel.org Signed-off-by: Bryan O'Donoghue Reviewed-by: Konrad Dybcio Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c index 04baa80494c66..4dba61b8d3f2a 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c @@ -476,7 +476,7 @@ static void csiphy_lanes_enable(struct csiphy_device *csiphy, settle_cnt = csiphy_settle_cnt_calc(link_freq, csiphy->timer_clk_rate); - val = is_gen2 ? BIT(7) : CSIPHY_3PH_CMN_CSI_COMMON_CTRL5_CLK_ENABLE; + val = CSIPHY_3PH_CMN_CSI_COMMON_CTRL5_CLK_ENABLE; for (i = 0; i < c->num_data; i++) val |= BIT(c->data[i].pos * 2); -- GitLab From e655d1ae9703286cef7fda8675cad62f649dc183 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Wed, 30 Aug 2023 16:16:14 +0100 Subject: [PATCH 0183/1451] media: qcom: camss: Fix set CSI2_RX_CFG1_VC_MODE when VC is greater than 3 VC_MODE = 0 implies a two bit VC address. VC_MODE = 1 is required for VCs with a larger address than two bits. Fixes: eebe6d00e9bf ("media: camss: Add support for CSID hardware version Titan 170") Cc: stable@vger.kernel.org Signed-off-by: Bryan O'Donoghue Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss-csid-gen2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen2.c b/drivers/media/platform/qcom/camss/camss-csid-gen2.c index 0f8ac29d038db..efc68f8b4de9e 100644 --- a/drivers/media/platform/qcom/camss/camss-csid-gen2.c +++ b/drivers/media/platform/qcom/camss/camss-csid-gen2.c @@ -449,6 +449,8 @@ static void __csid_configure_stream(struct csid_device *csid, u8 enable, u8 vc) writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG0); val = 1 << CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN; + if (vc > 3) + val |= 1 << CSI2_RX_CFG1_VC_MODE; val |= 1 << CSI2_RX_CFG1_MISR_EN; writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG1); -- GitLab From 87889f1b7ea40d2544b49c62092e6ef2792dced7 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Wed, 30 Aug 2023 16:16:15 +0100 Subject: [PATCH 0184/1451] media: qcom: camss: Fix csid-gen2 for test pattern generator In the current driver csid Test Pattern Generator (TPG) doesn't work. This change: - fixes writing frame width and height values into CSID_TPG_DT_n_CFG_0 - fixes the shift by one between test_pattern control value and the actual pattern. - drops fixed VC of 0x0a which testing showed prohibited some test patterns in the CSID to produce output. So that TPG starts working, but with the below limitations: - only test_pattern=9 works as it should - test_pattern=8 and test_pattern=7 produce black frame (all zeroes) - the rest of test_pattern's don't work (yavta doesn't get the data) - regardless of the CFA pattern set by 'media-ctl -V' the actual pixel order is always the same (RGGB for any RAW8 or RAW10P format in 4608x2592 resolution). Tested with: RAW10P format, VC0: media-ctl -V '"msm_csid0":0[fmt:SRGGB10/4608x2592 field:none]' media-ctl -V '"msm_vfe0_rdi0":0[fmt:SRGGB10/4608x2592 field:none]' media-ctl -l '"msm_csid0":1->"msm_vfe0_rdi0":0[1]' v4l2-ctl -d /dev/v4l-subdev6 -c test_pattern=9 yavta -B capture-mplane --capture=3 -n 3 -f SRGGB10P -s 4608x2592 /dev/video0 RAW10P format, VC1: media-ctl -V '"msm_csid0":2[fmt:SRGGB10/4608x2592 field:none]' media-ctl -V '"msm_vfe0_rdi1":0[fmt:SRGGB10/4608x2592 field:none]' media-ctl -l '"msm_csid0":2->"msm_vfe0_rdi1":0[1]' v4l2-ctl -d /dev/v4l-subdev6 -c test_pattern=9 yavta -B capture-mplane --capture=3 -n 3 -f SRGGB10P -s 4608x2592 /dev/video1 RAW8 format, VC0: media-ctl --reset media-ctl -V '"msm_csid0":0[fmt:SRGGB8/4608x2592 field:none]' media-ctl -V '"msm_vfe0_rdi0":0[fmt:SRGGB8/4608x2592 field:none]' media-ctl -l '"msm_csid0":1->"msm_vfe0_rdi0":0[1]' yavta -B capture-mplane --capture=3 -n 3 -f SRGGB8 -s 4608x2592 /dev/video0 Fixes: eebe6d00e9bf ("media: camss: Add support for CSID hardware version Titan 170") Cc: stable@vger.kernel.org Signed-off-by: Andrey Konovalov Signed-off-by: Bryan O'Donoghue Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss-csid-gen2.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen2.c b/drivers/media/platform/qcom/camss/camss-csid-gen2.c index efc68f8b4de9e..23acc387be5f0 100644 --- a/drivers/media/platform/qcom/camss/camss-csid-gen2.c +++ b/drivers/media/platform/qcom/camss/camss-csid-gen2.c @@ -355,9 +355,6 @@ static void __csid_configure_stream(struct csid_device *csid, u8 enable, u8 vc) u8 dt_id = vc; if (tg->enabled) { - /* Config Test Generator */ - vc = 0xa; - /* configure one DT, infinite frames */ val = vc << TPG_VC_CFG0_VC_NUM; val |= INTELEAVING_MODE_ONE_SHOT << TPG_VC_CFG0_LINE_INTERLEAVING_MODE; @@ -370,14 +367,14 @@ static void __csid_configure_stream(struct csid_device *csid, u8 enable, u8 vc) writel_relaxed(0x12345678, csid->base + CSID_TPG_LFSR_SEED); - val = input_format->height & 0x1fff << TPG_DT_n_CFG_0_FRAME_HEIGHT; - val |= input_format->width & 0x1fff << TPG_DT_n_CFG_0_FRAME_WIDTH; + val = (input_format->height & 0x1fff) << TPG_DT_n_CFG_0_FRAME_HEIGHT; + val |= (input_format->width & 0x1fff) << TPG_DT_n_CFG_0_FRAME_WIDTH; writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_0(0)); val = format->data_type << TPG_DT_n_CFG_1_DATA_TYPE; writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_1(0)); - val = tg->mode << TPG_DT_n_CFG_2_PAYLOAD_MODE; + val = (tg->mode - 1) << TPG_DT_n_CFG_2_PAYLOAD_MODE; val |= 0xBE << TPG_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD; val |= format->decode_format << TPG_DT_n_CFG_2_ENCODE_FORMAT; writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_2(0)); -- GitLab From ef876db6a2bf412b550fd3cbdfdcc73ca9959420 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 7 Apr 2023 15:28:31 +0200 Subject: [PATCH 0185/1451] dt-bindings: media: qcom,sdm845-venus-v2: Allow interconnect properties Allow the interconnect properties, which have been in use for ages. Signed-off-by: Konrad Dybcio Acked-by: Rob Herring Signed-off-by: Hans Verkuil --- .../devicetree/bindings/media/qcom,sdm845-venus-v2.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/media/qcom,sdm845-venus-v2.yaml b/Documentation/devicetree/bindings/media/qcom,sdm845-venus-v2.yaml index d5f80976f4cfe..6228fd2b32463 100644 --- a/Documentation/devicetree/bindings/media/qcom,sdm845-venus-v2.yaml +++ b/Documentation/devicetree/bindings/media/qcom,sdm845-venus-v2.yaml @@ -48,6 +48,14 @@ properties: iommus: maxItems: 2 + interconnects: + maxItems: 2 + + interconnect-names: + items: + - const: video-mem + - const: cpu-cfg + operating-points-v2: true opp-table: type: object -- GitLab From 89936bfbdf11f8758b852e7225a02e5fee57a1cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20D=C3=B8rum?= Date: Thu, 13 Apr 2023 12:54:36 +0200 Subject: [PATCH 0186/1451] media: qcom/camss: use 1X16 formats instead of 2X8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Platforms with qcom-camss use CSI-2, which means 1X16 is more correct than 2X8. The fact that qcom-camss supported only 2X8 meant it was incompatible with camera sensors it should have been compatible with. For example, the ov5645 driver (correctly) reports that its format is UYVY8_1X16 (after ba449bb56203aedc4530a82b0f3f83358808b7f2). Since qcom-camss only supports 2X8, the qcom-camss system is incompatible with the ov5645 driver, even though they should be compatible. This patch replaces all uses of UYVY8_2X8/VYUY8_2X8/YUYV8_2X8/YVYU8_2X8 with the equivalent 1X16 formats. Signed-off-by: Martin Dørum Acked-by: Bryan O'Donoghue Signed-off-by: Hans Verkuil --- .../platform/qcom/camss/camss-csid-4-1.c | 8 +- .../platform/qcom/camss/camss-csid-4-7.c | 8 +- .../platform/qcom/camss/camss-csid-gen2.c | 8 +- .../media/platform/qcom/camss/camss-csid.c | 6 +- .../media/platform/qcom/camss/camss-csiphy.c | 28 ++--- .../media/platform/qcom/camss/camss-ispif.c | 20 ++-- .../media/platform/qcom/camss/camss-vfe-4-1.c | 16 +-- .../media/platform/qcom/camss/camss-vfe-4-7.c | 16 +-- .../media/platform/qcom/camss/camss-vfe-4-8.c | 16 +-- drivers/media/platform/qcom/camss/camss-vfe.c | 100 +++++++++--------- .../media/platform/qcom/camss/camss-video.c | 64 +++++------ 11 files changed, 145 insertions(+), 145 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csid-4-1.c b/drivers/media/platform/qcom/camss/camss-csid-4-1.c index d2aec0679dfc0..dd49a40e6a704 100644 --- a/drivers/media/platform/qcom/camss/camss-csid-4-1.c +++ b/drivers/media/platform/qcom/camss/camss-csid-4-1.c @@ -47,28 +47,28 @@ static const struct csid_format csid_formats[] = { { - MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_UYVY8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, 2, }, { - MEDIA_BUS_FMT_VYUY8_2X8, + MEDIA_BUS_FMT_VYUY8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, 2, }, { - MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_YUYV8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, 2, }, { - MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_YVYU8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, diff --git a/drivers/media/platform/qcom/camss/camss-csid-4-7.c b/drivers/media/platform/qcom/camss/camss-csid-4-7.c index e7436ec6d02bf..6b26e036294e4 100644 --- a/drivers/media/platform/qcom/camss/camss-csid-4-7.c +++ b/drivers/media/platform/qcom/camss/camss-csid-4-7.c @@ -46,28 +46,28 @@ static const struct csid_format csid_formats[] = { { - MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_UYVY8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, 2, }, { - MEDIA_BUS_FMT_VYUY8_2X8, + MEDIA_BUS_FMT_VYUY8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, 2, }, { - MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_YUYV8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, 2, }, { - MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_YVYU8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen2.c b/drivers/media/platform/qcom/camss/camss-csid-gen2.c index 23acc387be5f0..6ba2b10326444 100644 --- a/drivers/media/platform/qcom/camss/camss-csid-gen2.c +++ b/drivers/media/platform/qcom/camss/camss-csid-gen2.c @@ -179,28 +179,28 @@ static const struct csid_format csid_formats[] = { { - MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_UYVY8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, 2, }, { - MEDIA_BUS_FMT_VYUY8_2X8, + MEDIA_BUS_FMT_VYUY8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, 2, }, { - MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_YUYV8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, 2, }, { - MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_YVYU8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index 6360314f04a63..9d7fb1adebb98 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -307,7 +307,7 @@ static void csid_try_format(struct csid_device *csid, /* If not found, use UYVY as default */ if (i >= csid->nformats) - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; fmt->width = clamp_t(u32, fmt->width, 1, 8191); fmt->height = clamp_t(u32, fmt->height, 1, 8191); @@ -336,7 +336,7 @@ static void csid_try_format(struct csid_device *csid, /* If not found, use UYVY as default */ if (i >= csid->nformats) - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; fmt->width = clamp_t(u32, fmt->width, 1, 8191); fmt->height = clamp_t(u32, fmt->height, 1, 8191); @@ -503,7 +503,7 @@ static int csid_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) .which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE, .format = { - .code = MEDIA_BUS_FMT_UYVY8_2X8, + .code = MEDIA_BUS_FMT_UYVY8_1X16, .width = 1920, .height = 1080 } diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index 3f726a7237f56..c5ae9c61ee0b1 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -30,10 +30,10 @@ struct csiphy_format { }; static const struct csiphy_format csiphy_formats_8x16[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, - { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, - { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, - { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, + { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, + { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, + { MEDIA_BUS_FMT_YVYU8_1X16, 8 }, { MEDIA_BUS_FMT_SBGGR8_1X8, 8 }, { MEDIA_BUS_FMT_SGBRG8_1X8, 8 }, { MEDIA_BUS_FMT_SGRBG8_1X8, 8 }, @@ -50,10 +50,10 @@ static const struct csiphy_format csiphy_formats_8x16[] = { }; static const struct csiphy_format csiphy_formats_8x96[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, - { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, - { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, - { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, + { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, + { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, + { MEDIA_BUS_FMT_YVYU8_1X16, 8 }, { MEDIA_BUS_FMT_SBGGR8_1X8, 8 }, { MEDIA_BUS_FMT_SGBRG8_1X8, 8 }, { MEDIA_BUS_FMT_SGRBG8_1X8, 8 }, @@ -74,10 +74,10 @@ static const struct csiphy_format csiphy_formats_8x96[] = { }; static const struct csiphy_format csiphy_formats_sdm845[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, - { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, - { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, - { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, + { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, + { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, + { MEDIA_BUS_FMT_YVYU8_1X16, 8 }, { MEDIA_BUS_FMT_SBGGR8_1X8, 8 }, { MEDIA_BUS_FMT_SGBRG8_1X8, 8 }, { MEDIA_BUS_FMT_SGRBG8_1X8, 8 }, @@ -357,7 +357,7 @@ static void csiphy_try_format(struct csiphy_device *csiphy, /* If not found, use UYVY as default */ if (i >= csiphy->nformats) - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; fmt->width = clamp_t(u32, fmt->width, 1, 8191); fmt->height = clamp_t(u32, fmt->height, 1, 8191); @@ -527,7 +527,7 @@ static int csiphy_init_formats(struct v4l2_subdev *sd, .which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE, .format = { - .code = MEDIA_BUS_FMT_UYVY8_2X8, + .code = MEDIA_BUS_FMT_UYVY8_1X16, .width = 1920, .height = 1080 } diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index b713f5b86aba6..1c7e4b1b49401 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -106,10 +106,10 @@ enum ispif_intf_cmd { }; static const u32 ispif_formats_8x16[] = { - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_VYUY8_2X8, - MEDIA_BUS_FMT_YUYV8_2X8, - MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_UYVY8_1X16, + MEDIA_BUS_FMT_VYUY8_1X16, + MEDIA_BUS_FMT_YUYV8_1X16, + MEDIA_BUS_FMT_YVYU8_1X16, MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8, @@ -126,10 +126,10 @@ static const u32 ispif_formats_8x16[] = { }; static const u32 ispif_formats_8x96[] = { - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_VYUY8_2X8, - MEDIA_BUS_FMT_YUYV8_2X8, - MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_UYVY8_1X16, + MEDIA_BUS_FMT_VYUY8_1X16, + MEDIA_BUS_FMT_YUYV8_1X16, + MEDIA_BUS_FMT_YVYU8_1X16, MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8, @@ -911,7 +911,7 @@ static void ispif_try_format(struct ispif_line *line, /* If not found, use UYVY as default */ if (i >= line->nformats) - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; fmt->width = clamp_t(u32, fmt->width, 1, 8191); fmt->height = clamp_t(u32, fmt->height, 1, 8191); @@ -1078,7 +1078,7 @@ static int ispif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) .which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE, .format = { - .code = MEDIA_BUS_FMT_UYVY8_2X8, + .code = MEDIA_BUS_FMT_UYVY8_1X16, .width = 1920, .height = 1080 } diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c index 42047b11ba529..bc309f326f519 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c @@ -614,20 +614,20 @@ static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line) writel_relaxed(val, vfe->base + VFE_0_DEMUX_GAIN_1); switch (line->fmt[MSM_VFE_PAD_SINK].code) { - case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_1X16: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YUYV; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YUYV; break; - case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_YVYU8_1X16: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YVYU; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YVYU; break; - case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_1X16: default: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_UYVY; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_UYVY; break; - case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_1X16: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_VYUY; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_VYUY; break; @@ -775,17 +775,17 @@ static void vfe_set_camif_cfg(struct vfe_device *vfe, struct vfe_line *line) u32 val; switch (line->fmt[MSM_VFE_PAD_SINK].code) { - case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_1X16: val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR; break; - case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_YVYU8_1X16: val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCRYCB; break; - case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_1X16: default: val = VFE_0_CORE_CFG_PIXEL_PATTERN_CBYCRY; break; - case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_1X16: val = VFE_0_CORE_CFG_PIXEL_PATTERN_CRYCBY; break; } diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c index ab2d57bdf5e71..8acd76c9746ba 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c @@ -768,20 +768,20 @@ static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line) writel_relaxed(val, vfe->base + VFE_0_DEMUX_GAIN_1); switch (line->fmt[MSM_VFE_PAD_SINK].code) { - case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_1X16: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YUYV; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YUYV; break; - case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_YVYU8_1X16: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YVYU; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YVYU; break; - case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_1X16: default: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_UYVY; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_UYVY; break; - case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_1X16: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_VYUY; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_VYUY; break; @@ -941,17 +941,17 @@ static void vfe_set_camif_cfg(struct vfe_device *vfe, struct vfe_line *line) u32 val; switch (line->fmt[MSM_VFE_PAD_SINK].code) { - case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_1X16: val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR; break; - case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_YVYU8_1X16: val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCRYCB; break; - case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_1X16: default: val = VFE_0_CORE_CFG_PIXEL_PATTERN_CBYCRY; break; - case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_1X16: val = VFE_0_CORE_CFG_PIXEL_PATTERN_CRYCBY; break; } diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c index 7e6b62c930ac8..3a0167ecf873a 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c @@ -739,20 +739,20 @@ static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line) writel_relaxed(val, vfe->base + VFE_0_DEMUX_GAIN_1); switch (line->fmt[MSM_VFE_PAD_SINK].code) { - case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_1X16: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YUYV; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YUYV; break; - case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_YVYU8_1X16: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YVYU; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YVYU; break; - case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_1X16: default: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_UYVY; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_UYVY; break; - case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_1X16: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_VYUY; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_VYUY; break; @@ -873,17 +873,17 @@ static void vfe_set_camif_cfg(struct vfe_device *vfe, struct vfe_line *line) u32 val; switch (line->fmt[MSM_VFE_PAD_SINK].code) { - case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_1X16: val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR; break; - case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_YVYU8_1X16: val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCRYCB; break; - case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_1X16: default: val = VFE_0_CORE_CFG_PIXEL_PATTERN_CBYCRY; break; - case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_1X16: val = VFE_0_CORE_CFG_PIXEL_PATTERN_CRYCBY; break; } diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 965500b83d073..b021f81cef123 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -37,10 +37,10 @@ struct vfe_format { }; static const struct vfe_format formats_rdi_8x16[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, - { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, - { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, - { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, + { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, + { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, + { MEDIA_BUS_FMT_YVYU8_1X16, 8 }, { MEDIA_BUS_FMT_SBGGR8_1X8, 8 }, { MEDIA_BUS_FMT_SGBRG8_1X8, 8 }, { MEDIA_BUS_FMT_SGRBG8_1X8, 8 }, @@ -57,17 +57,17 @@ static const struct vfe_format formats_rdi_8x16[] = { }; static const struct vfe_format formats_pix_8x16[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, - { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, - { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, - { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, + { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, + { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, + { MEDIA_BUS_FMT_YVYU8_1X16, 8 }, }; static const struct vfe_format formats_rdi_8x96[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, - { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, - { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, - { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, + { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, + { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, + { MEDIA_BUS_FMT_YVYU8_1X16, 8 }, { MEDIA_BUS_FMT_SBGGR8_1X8, 8 }, { MEDIA_BUS_FMT_SGBRG8_1X8, 8 }, { MEDIA_BUS_FMT_SGRBG8_1X8, 8 }, @@ -90,17 +90,17 @@ static const struct vfe_format formats_rdi_8x96[] = { }; static const struct vfe_format formats_pix_8x96[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, - { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, - { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, - { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, + { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, + { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, + { MEDIA_BUS_FMT_YVYU8_1X16, 8 }, }; static const struct vfe_format formats_rdi_845[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, - { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, - { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, - { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, + { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, + { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, + { MEDIA_BUS_FMT_YVYU8_1X16, 8 }, { MEDIA_BUS_FMT_SBGGR8_1X8, 8 }, { MEDIA_BUS_FMT_SGBRG8_1X8, 8 }, { MEDIA_BUS_FMT_SGRBG8_1X8, 8 }, @@ -172,40 +172,40 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, if (vfe->camss->version == CAMSS_8x16) switch (sink_code) { - case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_1X16: { u32 src_code[] = { - MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YUYV8_1_5X8, }; return vfe_find_code(src_code, ARRAY_SIZE(src_code), index, src_req_code); } - case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_YVYU8_1X16: { u32 src_code[] = { - MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_YVYU8_1X16, MEDIA_BUS_FMT_YVYU8_1_5X8, }; return vfe_find_code(src_code, ARRAY_SIZE(src_code), index, src_req_code); } - case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_1X16: { u32 src_code[] = { - MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_UYVY8_1_5X8, }; return vfe_find_code(src_code, ARRAY_SIZE(src_code), index, src_req_code); } - case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_1X16: { u32 src_code[] = { - MEDIA_BUS_FMT_VYUY8_2X8, + MEDIA_BUS_FMT_VYUY8_1X16, MEDIA_BUS_FMT_VYUY8_1_5X8, }; @@ -223,52 +223,52 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, vfe->camss->version == CAMSS_845 || vfe->camss->version == CAMSS_8250) switch (sink_code) { - case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_1X16: { u32 src_code[] = { - MEDIA_BUS_FMT_YUYV8_2X8, - MEDIA_BUS_FMT_YVYU8_2X8, - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_VYUY8_2X8, + MEDIA_BUS_FMT_YUYV8_1X16, + MEDIA_BUS_FMT_YVYU8_1X16, + MEDIA_BUS_FMT_UYVY8_1X16, + MEDIA_BUS_FMT_VYUY8_1X16, MEDIA_BUS_FMT_YUYV8_1_5X8, }; return vfe_find_code(src_code, ARRAY_SIZE(src_code), index, src_req_code); } - case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_YVYU8_1X16: { u32 src_code[] = { - MEDIA_BUS_FMT_YVYU8_2X8, - MEDIA_BUS_FMT_YUYV8_2X8, - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_VYUY8_2X8, + MEDIA_BUS_FMT_YVYU8_1X16, + MEDIA_BUS_FMT_YUYV8_1X16, + MEDIA_BUS_FMT_UYVY8_1X16, + MEDIA_BUS_FMT_VYUY8_1X16, MEDIA_BUS_FMT_YVYU8_1_5X8, }; return vfe_find_code(src_code, ARRAY_SIZE(src_code), index, src_req_code); } - case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_1X16: { u32 src_code[] = { - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_YUYV8_2X8, - MEDIA_BUS_FMT_YVYU8_2X8, - MEDIA_BUS_FMT_VYUY8_2X8, + MEDIA_BUS_FMT_UYVY8_1X16, + MEDIA_BUS_FMT_YUYV8_1X16, + MEDIA_BUS_FMT_YVYU8_1X16, + MEDIA_BUS_FMT_VYUY8_1X16, MEDIA_BUS_FMT_UYVY8_1_5X8, }; return vfe_find_code(src_code, ARRAY_SIZE(src_code), index, src_req_code); } - case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_1X16: { u32 src_code[] = { - MEDIA_BUS_FMT_VYUY8_2X8, - MEDIA_BUS_FMT_YUYV8_2X8, - MEDIA_BUS_FMT_YVYU8_2X8, - MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_VYUY8_1X16, + MEDIA_BUS_FMT_YUYV8_1X16, + MEDIA_BUS_FMT_YVYU8_1X16, + MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_VYUY8_1_5X8, }; @@ -845,7 +845,7 @@ static void vfe_try_format(struct vfe_line *line, /* If not found, use UYVY as default */ if (i >= line->nformats) - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; fmt->width = clamp_t(u32, fmt->width, 1, 8191); fmt->height = clamp_t(u32, fmt->height, 1, 8191); @@ -1262,7 +1262,7 @@ static int vfe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) .which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE, .format = { - .code = MEDIA_BUS_FMT_UYVY8_2X8, + .code = MEDIA_BUS_FMT_UYVY8_1X16, .width = 1920, .height = 1080 } diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 8640db3060268..1d686aef92eaf 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -48,13 +48,13 @@ struct camss_format_info { }; static const struct camss_format_info formats_rdi_8x16[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, + { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, + { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_VYUY, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, + { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, + { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_YVYU, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1, { { 1, 1 } }, { { 1, 1 } }, { 8 } }, @@ -85,13 +85,13 @@ static const struct camss_format_info formats_rdi_8x16[] = { }; static const struct camss_format_info formats_rdi_8x96[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, + { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, + { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_VYUY, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, + { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, + { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_YVYU, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1, { { 1, 1 } }, { { 1, 1 } }, { 8 } }, @@ -134,13 +134,13 @@ static const struct camss_format_info formats_rdi_8x96[] = { }; static const struct camss_format_info formats_rdi_845[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, + { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, + { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_VYUY, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, + { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, + { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_YVYU, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1, { { 1, 1 } }, { { 1, 1 } }, { 8 } }, @@ -201,21 +201,21 @@ static const struct camss_format_info formats_pix_8x16[] = { { { 1, 1 } }, { { 2, 3 } }, { 8 } }, { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1, { { 1, 1 } }, { { 2, 3 } }, { 8 } }, - { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1, + { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_NV16, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1, + { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_NV16, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1, + { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_NV16, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1, + { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_NV16, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1, + { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_NV61, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1, + { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_NV61, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1, + { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_NV61, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1, + { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_NV61, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, }; @@ -236,29 +236,29 @@ static const struct camss_format_info formats_pix_8x96[] = { { { 1, 1 } }, { { 2, 3 } }, { 8 } }, { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1, { { 1, 1 } }, { { 2, 3 } }, { 8 } }, - { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1, + { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_NV16, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1, + { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_NV16, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1, + { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_NV16, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1, + { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_NV16, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1, + { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_NV61, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1, + { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_NV61, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1, + { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_NV61, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1, + { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_NV61, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, + { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, + { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_VYUY, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, + { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, + { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_YVYU, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, }; -- GitLab From afca12e35e711ae8f97e835a3704cc305592eac9 Mon Sep 17 00:00:00 2001 From: Reka Norman Date: Fri, 25 Aug 2023 12:43:54 +1000 Subject: [PATCH 0187/1451] media: cros-ec-cec: Use cros_ec_cmd to send host commands Use the cros_ec_cmd helper function to reduce the amount of boilerplate when sending host commands. Signed-off-by: Reka Norman Signed-off-by: Hans Verkuil --- .../media/cec/platform/cros-ec/cros-ec-cec.c | 44 +++++++------------ 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index c17faf002877d..8dd95fb385462 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -95,18 +95,14 @@ static int cros_ec_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr) { struct cros_ec_cec *cros_ec_cec = adap->priv; struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; - struct { - struct cros_ec_command msg; - struct ec_params_cec_set data; - } __packed msg = {}; + struct ec_params_cec_set params = { + .cmd = CEC_CMD_LOGICAL_ADDRESS, + .val = logical_addr, + }; int ret; - msg.msg.command = EC_CMD_CEC_SET; - msg.msg.outsize = sizeof(msg.data); - msg.data.cmd = CEC_CMD_LOGICAL_ADDRESS; - msg.data.val = logical_addr; - - ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg); + ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_SET, ¶ms, sizeof(params), + NULL, 0); if (ret < 0) { dev_err(cros_ec->dev, "error setting CEC logical address on EC: %d\n", ret); @@ -121,17 +117,13 @@ static int cros_ec_cec_transmit(struct cec_adapter *adap, u8 attempts, { struct cros_ec_cec *cros_ec_cec = adap->priv; struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; - struct { - struct cros_ec_command msg; - struct ec_params_cec_write data; - } __packed msg = {}; + struct ec_params_cec_write params; int ret; - msg.msg.command = EC_CMD_CEC_WRITE_MSG; - msg.msg.outsize = cec_msg->len; - memcpy(msg.data.msg, cec_msg->msg, cec_msg->len); + memcpy(params.msg, cec_msg->msg, cec_msg->len); - ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg); + ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_WRITE_MSG, ¶ms, + cec_msg->len, NULL, 0); if (ret < 0) { dev_err(cros_ec->dev, "error writing CEC msg on EC: %d\n", ret); @@ -145,18 +137,14 @@ static int cros_ec_cec_adap_enable(struct cec_adapter *adap, bool enable) { struct cros_ec_cec *cros_ec_cec = adap->priv; struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; - struct { - struct cros_ec_command msg; - struct ec_params_cec_set data; - } __packed msg = {}; + struct ec_params_cec_set params = { + .cmd = CEC_CMD_ENABLE, + .val = enable, + }; int ret; - msg.msg.command = EC_CMD_CEC_SET; - msg.msg.outsize = sizeof(msg.data); - msg.data.cmd = CEC_CMD_ENABLE; - msg.data.val = enable; - - ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg); + ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_SET, ¶ms, sizeof(params), + NULL, 0); if (ret < 0) { dev_err(cros_ec->dev, "error %sabling CEC on EC: %d\n", -- GitLab From 4d0e179a42879f7d76a5b95a2e7e7a5afa33954a Mon Sep 17 00:00:00 2001 From: Reka Norman Date: Fri, 25 Aug 2023 12:43:55 +1000 Subject: [PATCH 0188/1451] media: cros-ec-cec: Manage an array of ports To support multiple CEC ports, change cros_ec_cec to contain an array of ports, each with their own CEC adapter, etc. For now, only create a single port and use that port everywhere, so there is no functional change. Support for multiple ports will be added in the following patches. Signed-off-by: Reka Norman Signed-off-by: Hans Verkuil --- .../media/cec/platform/cros-ec/cros-ec-cec.c | 147 +++++++++++++----- .../linux/platform_data/cros_ec_commands.h | 2 + 2 files changed, 110 insertions(+), 39 deletions(-) diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index 8dd95fb385462..d76a25ae0cf18 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -21,21 +21,40 @@ #define DRV_NAME "cros-ec-cec" +/* Only one port is supported for now */ +#define CEC_NUM_PORTS 1 +#define CEC_PORT 0 + /** - * struct cros_ec_cec - Driver data for EC CEC + * struct cros_ec_cec_port - Driver data for a single EC CEC port * - * @cros_ec: Pointer to EC device - * @notifier: Notifier info for responding to EC events + * @port_num: port number * @adap: CEC adapter * @notify: CEC notifier pointer * @rx_msg: storage for a received message + * @cros_ec_cec: pointer to the parent struct */ -struct cros_ec_cec { - struct cros_ec_device *cros_ec; - struct notifier_block notifier; +struct cros_ec_cec_port { + int port_num; struct cec_adapter *adap; struct cec_notifier *notify; struct cec_msg rx_msg; + struct cros_ec_cec *cros_ec_cec; +}; + +/** + * struct cros_ec_cec - Driver data for EC CEC + * + * @cros_ec: Pointer to EC device + * @notifier: Notifier info for responding to EC events + * @num_ports: Number of CEC ports + * @ports: Array of ports + */ +struct cros_ec_cec { + struct cros_ec_device *cros_ec; + struct notifier_block notifier; + int num_ports; + struct cros_ec_cec_port *ports[EC_CEC_MAX_PORTS]; }; static void handle_cec_message(struct cros_ec_cec *cros_ec_cec) @@ -43,27 +62,28 @@ static void handle_cec_message(struct cros_ec_cec *cros_ec_cec) struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; uint8_t *cec_message = cros_ec->event_data.data.cec_message; unsigned int len = cros_ec->event_size; + struct cros_ec_cec_port *port = cros_ec_cec->ports[CEC_PORT]; if (len > CEC_MAX_MSG_SIZE) len = CEC_MAX_MSG_SIZE; - cros_ec_cec->rx_msg.len = len; - memcpy(cros_ec_cec->rx_msg.msg, cec_message, len); + port->rx_msg.len = len; + memcpy(port->rx_msg.msg, cec_message, len); - cec_received_msg(cros_ec_cec->adap, &cros_ec_cec->rx_msg); + cec_received_msg(port->adap, &port->rx_msg); } static void handle_cec_event(struct cros_ec_cec *cros_ec_cec) { struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; uint32_t events = cros_ec->event_data.data.cec_events; + struct cros_ec_cec_port *port = cros_ec_cec->ports[CEC_PORT]; if (events & EC_MKBP_CEC_SEND_OK) - cec_transmit_attempt_done(cros_ec_cec->adap, - CEC_TX_STATUS_OK); + cec_transmit_attempt_done(port->adap, CEC_TX_STATUS_OK); /* FW takes care of all retries, tell core to avoid more retries */ if (events & EC_MKBP_CEC_SEND_FAILED) - cec_transmit_attempt_done(cros_ec_cec->adap, + cec_transmit_attempt_done(port->adap, CEC_TX_STATUS_MAX_RETRIES | CEC_TX_STATUS_NACK); } @@ -93,7 +113,8 @@ static int cros_ec_cec_event(struct notifier_block *nb, static int cros_ec_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr) { - struct cros_ec_cec *cros_ec_cec = adap->priv; + struct cros_ec_cec_port *port = adap->priv; + struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec; struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; struct ec_params_cec_set params = { .cmd = CEC_CMD_LOGICAL_ADDRESS, @@ -115,7 +136,8 @@ static int cros_ec_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr) static int cros_ec_cec_transmit(struct cec_adapter *adap, u8 attempts, u32 signal_free_time, struct cec_msg *cec_msg) { - struct cros_ec_cec *cros_ec_cec = adap->priv; + struct cros_ec_cec_port *port = adap->priv; + struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec; struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; struct ec_params_cec_write params; int ret; @@ -135,7 +157,8 @@ static int cros_ec_cec_transmit(struct cec_adapter *adap, u8 attempts, static int cros_ec_cec_adap_enable(struct cec_adapter *adap, bool enable) { - struct cros_ec_cec *cros_ec_cec = adap->priv; + struct cros_ec_cec_port *port = adap->priv; + struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec; struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; struct ec_params_cec_set params = { .cmd = CEC_CMD_ENABLE, @@ -260,11 +283,55 @@ static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, #endif +static int cros_ec_cec_init_port(struct device *dev, + struct cros_ec_cec *cros_ec_cec, + int port_num, struct device *hdmi_dev, + const char *conn) +{ + struct cros_ec_cec_port *port; + int ret; + + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + port->cros_ec_cec = cros_ec_cec; + port->port_num = port_num; + + port->adap = cec_allocate_adapter(&cros_ec_cec_ops, port, DRV_NAME, + CEC_CAP_DEFAULTS | + CEC_CAP_CONNECTOR_INFO, 1); + if (IS_ERR(port->adap)) + return PTR_ERR(port->adap); + + port->notify = cec_notifier_cec_adap_register(hdmi_dev, conn, + port->adap); + if (!port->notify) { + ret = -ENOMEM; + goto out_probe_adapter; + } + + ret = cec_register_adapter(port->adap, dev); + if (ret < 0) + goto out_probe_notify; + + cros_ec_cec->ports[port_num] = port; + + return 0; + +out_probe_notify: + cec_notifier_cec_adap_unregister(port->notify, port->adap); +out_probe_adapter: + cec_delete_adapter(port->adap); + return ret; +} + static int cros_ec_cec_probe(struct platform_device *pdev) { struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent); struct cros_ec_device *cros_ec = ec_dev->ec_dev; struct cros_ec_cec *cros_ec_cec; + struct cros_ec_cec_port *port; struct device *hdmi_dev; const char *conn = NULL; int ret; @@ -283,18 +350,13 @@ static int cros_ec_cec_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); - cros_ec_cec->adap = cec_allocate_adapter(&cros_ec_cec_ops, cros_ec_cec, - DRV_NAME, - CEC_CAP_DEFAULTS | - CEC_CAP_CONNECTOR_INFO, 1); - if (IS_ERR(cros_ec_cec->adap)) - return PTR_ERR(cros_ec_cec->adap); + cros_ec_cec->num_ports = CEC_NUM_PORTS; - cros_ec_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, conn, - cros_ec_cec->adap); - if (!cros_ec_cec->notify) { - ret = -ENOMEM; - goto out_probe_adapter; + for (int i = 0; i < cros_ec_cec->num_ports; i++) { + ret = cros_ec_cec_init_port(&pdev->dev, cros_ec_cec, i, + hdmi_dev, conn); + if (ret) + goto unregister_ports; } /* Get CEC events from the EC. */ @@ -303,20 +365,24 @@ static int cros_ec_cec_probe(struct platform_device *pdev) &cros_ec_cec->notifier); if (ret) { dev_err(&pdev->dev, "failed to register notifier\n"); - goto out_probe_notify; + goto unregister_ports; } - ret = cec_register_adapter(cros_ec_cec->adap, &pdev->dev); - if (ret < 0) - goto out_probe_notify; - return 0; -out_probe_notify: - cec_notifier_cec_adap_unregister(cros_ec_cec->notify, - cros_ec_cec->adap); -out_probe_adapter: - cec_delete_adapter(cros_ec_cec->adap); +unregister_ports: + /* + * Unregister any adapters which have been registered. We don't add the + * port to the array until the adapter has been registered successfully, + * so any non-NULL ports must have been registered. + */ + for (int i = 0; i < cros_ec_cec->num_ports; i++) { + port = cros_ec_cec->ports[i]; + if (!port) + break; + cec_notifier_cec_adap_unregister(port->notify, port->adap); + cec_unregister_adapter(port->adap); + } return ret; } @@ -324,6 +390,7 @@ static void cros_ec_cec_remove(struct platform_device *pdev) { struct cros_ec_cec *cros_ec_cec = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; + struct cros_ec_cec_port *port; int ret; /* @@ -337,9 +404,11 @@ static void cros_ec_cec_remove(struct platform_device *pdev) if (ret) dev_err(dev, "failed to unregister notifier\n"); - cec_notifier_cec_adap_unregister(cros_ec_cec->notify, - cros_ec_cec->adap); - cec_unregister_adapter(cros_ec_cec->adap); + for (int i = 0; i < cros_ec_cec->num_ports; i++) { + port = cros_ec_cec->ports[i]; + cec_notifier_cec_adap_unregister(port->notify, port->adap); + cec_unregister_adapter(port->adap); + } } static struct platform_driver cros_ec_cec_driver = { diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index ab721cf13a986..cb2ddd10a6137 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -4436,6 +4436,8 @@ struct ec_response_i2c_passthru_protect { * These commands are for sending and receiving message via HDMI CEC */ +#define EC_CEC_MAX_PORTS 16 + #define MAX_CEC_MSG_LEN 16 /* CEC message from the AP to be written on the CEC bus */ -- GitLab From e90bd1fe7cda1aa267fe683e392b4433ec2dc0d3 Mon Sep 17 00:00:00 2001 From: Reka Norman Date: Fri, 25 Aug 2023 12:43:56 +1000 Subject: [PATCH 0189/1451] media: cros-ec-cec: Support multiple ports in set/get host commands Reuse the top four bits of the cmd field to specify the port number. The reason for doing this as opposed to adding a separate uint8_t field is it avoids the need to add new versions of these commands. The change is backwards compatible since these bits were previously always zero, so the default behaviour is to always operate on port 0. Signed-off-by: Reka Norman Signed-off-by: Hans Verkuil --- drivers/media/cec/platform/cros-ec/cros-ec-cec.c | 2 ++ include/linux/platform_data/cros_ec_commands.h | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index d76a25ae0cf18..e969031e1e0e3 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -118,6 +118,7 @@ static int cros_ec_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr) struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; struct ec_params_cec_set params = { .cmd = CEC_CMD_LOGICAL_ADDRESS, + .port = port->port_num, .val = logical_addr, }; int ret; @@ -162,6 +163,7 @@ static int cros_ec_cec_adap_enable(struct cec_adapter *adap, bool enable) struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; struct ec_params_cec_set params = { .cmd = CEC_CMD_ENABLE, + .port = port->port_num, .val = enable, }; int ret; diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index cb2ddd10a6137..e8bb05db360f1 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -4457,13 +4457,15 @@ struct ec_params_cec_write { /** * struct ec_params_cec_set - CEC parameters set * @cmd: parameter type, can be CEC_CMD_ENABLE or CEC_CMD_LOGICAL_ADDRESS + * @port: CEC port to set the parameter on * @val: in case cmd is CEC_CMD_ENABLE, this field can be 0 to disable CEC * or 1 to enable CEC functionality, in case cmd is * CEC_CMD_LOGICAL_ADDRESS, this field encodes the requested logical * address between 0 and 15 or 0xff to unregister */ struct ec_params_cec_set { - uint8_t cmd; /* enum cec_command */ + uint8_t cmd : 4; /* enum cec_command */ + uint8_t port : 4; uint8_t val; } __ec_align1; @@ -4473,9 +4475,11 @@ struct ec_params_cec_set { /** * struct ec_params_cec_get - CEC parameters get * @cmd: parameter type, can be CEC_CMD_ENABLE or CEC_CMD_LOGICAL_ADDRESS + * @port: CEC port to get the parameter on */ struct ec_params_cec_get { - uint8_t cmd; /* enum cec_command */ + uint8_t cmd : 4; /* enum cec_command */ + uint8_t port : 4; } __ec_align1; /** -- GitLab From adbfc747ddfb48c06d238640e16939916b7a4494 Mon Sep 17 00:00:00 2001 From: Reka Norman Date: Fri, 25 Aug 2023 12:43:57 +1000 Subject: [PATCH 0190/1451] media: cros-ec-cec: Support multiple ports in write command Add a v1 of the CEC write command which contains a port parameter. Check which versions of the write command the EC supports and use the highest supported version. If it only supports v0, check that there is only one port. With v0, the EC will assume all write commands are for port 0. Signed-off-by: Reka Norman Signed-off-by: Hans Verkuil --- .../media/cec/platform/cros-ec/cros-ec-cec.c | 54 +++++++++++++++++-- .../linux/platform_data/cros_ec_commands.h | 12 +++++ 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index e969031e1e0e3..d674a432dfdd1 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -47,12 +47,14 @@ struct cros_ec_cec_port { * * @cros_ec: Pointer to EC device * @notifier: Notifier info for responding to EC events + * @write_cmd_version: Highest supported version of EC_CMD_CEC_WRITE_MSG. * @num_ports: Number of CEC ports * @ports: Array of ports */ struct cros_ec_cec { struct cros_ec_device *cros_ec; struct notifier_block notifier; + int write_cmd_version; int num_ports; struct cros_ec_cec_port *ports[EC_CEC_MAX_PORTS]; }; @@ -141,12 +143,22 @@ static int cros_ec_cec_transmit(struct cec_adapter *adap, u8 attempts, struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec; struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; struct ec_params_cec_write params; + struct ec_params_cec_write_v1 params_v1; int ret; - memcpy(params.msg, cec_msg->msg, cec_msg->len); + if (cros_ec_cec->write_cmd_version == 0) { + memcpy(params.msg, cec_msg->msg, cec_msg->len); + ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_WRITE_MSG, ¶ms, + cec_msg->len, NULL, 0); + } else { + params_v1.port = port->port_num; + params_v1.msg_len = cec_msg->len; + memcpy(params_v1.msg, cec_msg->msg, cec_msg->len); + ret = cros_ec_cmd(cros_ec, cros_ec_cec->write_cmd_version, + EC_CMD_CEC_WRITE_MSG, ¶ms_v1, + sizeof(params_v1), NULL, 0); + } - ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_WRITE_MSG, ¶ms, - cec_msg->len, NULL, 0); if (ret < 0) { dev_err(cros_ec->dev, "error writing CEC msg on EC: %d\n", ret); @@ -285,6 +297,38 @@ static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, #endif +static int cros_ec_cec_get_write_cmd_version(struct cros_ec_cec *cros_ec_cec) +{ + struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; + struct ec_params_get_cmd_versions_v1 params = { + .cmd = EC_CMD_CEC_WRITE_MSG, + }; + struct ec_response_get_cmd_versions response; + int ret; + + ret = cros_ec_cmd(cros_ec, 1, EC_CMD_GET_CMD_VERSIONS, ¶ms, + sizeof(params), &response, sizeof(response)); + if (ret < 0) { + dev_err(cros_ec->dev, + "error getting CEC write command version: %d\n", ret); + return ret; + } + + if (response.version_mask & EC_VER_MASK(1)) { + cros_ec_cec->write_cmd_version = 1; + } else { + if (cros_ec_cec->num_ports != 1) { + dev_err(cros_ec->dev, + "v0 write command only supports 1 port, %d reported\n", + cros_ec_cec->num_ports); + return -EINVAL; + } + cros_ec_cec->write_cmd_version = 0; + } + + return 0; +} + static int cros_ec_cec_init_port(struct device *dev, struct cros_ec_cec *cros_ec_cec, int port_num, struct device *hdmi_dev, @@ -354,6 +398,10 @@ static int cros_ec_cec_probe(struct platform_device *pdev) cros_ec_cec->num_ports = CEC_NUM_PORTS; + ret = cros_ec_cec_get_write_cmd_version(cros_ec_cec); + if (ret) + return ret; + for (int i = 0; i < cros_ec_cec->num_ports; i++) { ret = cros_ec_cec_init_port(&pdev->dev, cros_ec_cec, i, hdmi_dev, conn); diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index e8bb05db360f1..9a0c6e28f3704 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -4451,6 +4451,18 @@ struct ec_params_cec_write { uint8_t msg[MAX_CEC_MSG_LEN]; } __ec_align1; +/** + * struct ec_params_cec_write_v1 - Message to write to the CEC bus + * @port: CEC port to write the message on + * @msg_len: length of msg in bytes + * @msg: message content to write to the CEC bus + */ +struct ec_params_cec_write_v1 { + uint8_t port; + uint8_t msg_len; + uint8_t msg[MAX_CEC_MSG_LEN]; +} __ec_align1; + /* Set various CEC parameters */ #define EC_CMD_CEC_SET 0x00BA -- GitLab From 1cabf52639d16428bc0d61028dcaf38e29c5f3b5 Mon Sep 17 00:00:00 2001 From: Reka Norman Date: Fri, 25 Aug 2023 12:43:58 +1000 Subject: [PATCH 0191/1451] media: cros-ec-cec: Support multiple ports in MKBP cec_events Use the top four bits of the cec_events MKBP event to store the port number. Signed-off-by: Reka Norman Signed-off-by: Hans Verkuil --- drivers/media/cec/platform/cros-ec/cros-ec-cec.c | 13 +++++++++++-- include/linux/platform_data/cros_ec_commands.h | 10 ++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index d674a432dfdd1..18f78b7e034a1 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -77,8 +77,17 @@ static void handle_cec_message(struct cros_ec_cec *cros_ec_cec) static void handle_cec_event(struct cros_ec_cec *cros_ec_cec) { struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; - uint32_t events = cros_ec->event_data.data.cec_events; - struct cros_ec_cec_port *port = cros_ec_cec->ports[CEC_PORT]; + uint32_t cec_events = cros_ec->event_data.data.cec_events; + uint32_t port_num = EC_MKBP_EVENT_CEC_GET_PORT(cec_events); + uint32_t events = EC_MKBP_EVENT_CEC_GET_EVENTS(cec_events); + struct cros_ec_cec_port *port; + + if (port_num >= cros_ec_cec->num_ports) { + dev_err(cros_ec->dev, + "received CEC event for invalid port %d\n", port_num); + return; + } + port = cros_ec_cec->ports[port_num]; if (events & EC_MKBP_CEC_SEND_OK) cec_transmit_attempt_done(port->adap, CEC_TX_STATUS_OK); diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index 9a0c6e28f3704..b7e8573a8a495 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -4440,6 +4440,16 @@ struct ec_response_i2c_passthru_protect { #define MAX_CEC_MSG_LEN 16 +/* + * Helper macros for packing/unpacking cec_events. + * bits[27:0] : bitmask of events from enum mkbp_cec_event + * bits[31:28]: port number + */ +#define EC_MKBP_EVENT_CEC_PACK(events, port) \ + (((events) & GENMASK(27, 0)) | (((port) & 0xf) << 28)) +#define EC_MKBP_EVENT_CEC_GET_EVENTS(event) ((event) & GENMASK(27, 0)) +#define EC_MKBP_EVENT_CEC_GET_PORT(event) (((event) >> 28) & 0xf) + /* CEC message from the AP to be written on the CEC bus */ #define EC_CMD_CEC_WRITE_MSG 0x00B8 -- GitLab From 425d20518c54bc6d66d733fb117a9a4046932d50 Mon Sep 17 00:00:00 2001 From: Reka Norman Date: Fri, 25 Aug 2023 12:43:59 +1000 Subject: [PATCH 0192/1451] media: cros-ec-cec: Support receiving messages from multiple ports Currently, received messages are sent from the EC in the cec_message MKBP event. Since the size of ec_response_get_next_data_v1 is 16 bytes, which is also the maximum size of a CEC message, there is no space to add a port parameter. Increasing the size of ec_response_get_next_data_v1 is an option, but this would increase EC-kernel traffic for all MKBP event types. Instead, use an event to notify that data is ready, and add a new read command to read the data. For backwards compatibility with old EC firmware, continue to handle cec_message events as well. Signed-off-by: Reka Norman Signed-off-by: Hans Verkuil --- .../media/cec/platform/cros-ec/cros-ec-cec.c | 59 +++++++++++++++++-- .../linux/platform_data/cros_ec_commands.h | 23 ++++++++ 2 files changed, 76 insertions(+), 6 deletions(-) diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index 18f78b7e034a1..6989e63c05bea 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -59,19 +59,63 @@ struct cros_ec_cec { struct cros_ec_cec_port *ports[EC_CEC_MAX_PORTS]; }; +static void cros_ec_cec_received_message(struct cros_ec_cec_port *port, + uint8_t *msg, uint8_t len) +{ + if (len > CEC_MAX_MSG_SIZE) + len = CEC_MAX_MSG_SIZE; + + port->rx_msg.len = len; + memcpy(port->rx_msg.msg, msg, len); + + cec_received_msg(port->adap, &port->rx_msg); +} + static void handle_cec_message(struct cros_ec_cec *cros_ec_cec) { struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; uint8_t *cec_message = cros_ec->event_data.data.cec_message; unsigned int len = cros_ec->event_size; - struct cros_ec_cec_port *port = cros_ec_cec->ports[CEC_PORT]; + struct cros_ec_cec_port *port; + /* + * There are two ways of receiving CEC messages: + * 1. Old EC firmware which only supports one port sends the data in a + * cec_message MKBP event. + * 2. New EC firmware which supports multiple ports uses + * EC_MKBP_CEC_HAVE_DATA to notify that data is ready and + * EC_CMD_CEC_READ_MSG to read it. + * Check that the EC only has one CEC port, and then we can assume the + * message is from port 0. + */ + if (cros_ec_cec->num_ports != 1) { + dev_err(cros_ec->dev, + "received cec_message on device with %d ports\n", + cros_ec_cec->num_ports); + return; + } + port = cros_ec_cec->ports[0]; - if (len > CEC_MAX_MSG_SIZE) - len = CEC_MAX_MSG_SIZE; - port->rx_msg.len = len; - memcpy(port->rx_msg.msg, cec_message, len); + cros_ec_cec_received_message(port, cec_message, len); +} - cec_received_msg(port->adap, &port->rx_msg); +static void cros_ec_cec_read_message(struct cros_ec_cec_port *port) +{ + struct cros_ec_device *cros_ec = port->cros_ec_cec->cros_ec; + struct ec_params_cec_read params = { + .port = port->port_num, + }; + struct ec_response_cec_read response; + int ret; + + ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_READ_MSG, ¶ms, + sizeof(params), &response, sizeof(response)); + if (ret < 0) { + dev_err(cros_ec->dev, + "error reading CEC message on EC: %d\n", ret); + return; + } + + cros_ec_cec_received_message(port, response.msg, response.msg_len); } static void handle_cec_event(struct cros_ec_cec *cros_ec_cec) @@ -97,6 +141,9 @@ static void handle_cec_event(struct cros_ec_cec *cros_ec_cec) cec_transmit_attempt_done(port->adap, CEC_TX_STATUS_MAX_RETRIES | CEC_TX_STATUS_NACK); + + if (events & EC_MKBP_CEC_HAVE_DATA) + cros_ec_cec_read_message(port); } static int cros_ec_cec_event(struct notifier_block *nb, diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index b7e8573a8a495..ad61c7ff0b285 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -4473,6 +4473,27 @@ struct ec_params_cec_write_v1 { uint8_t msg[MAX_CEC_MSG_LEN]; } __ec_align1; +/* CEC message read from a CEC bus reported back to the AP */ +#define EC_CMD_CEC_READ_MSG 0x00B9 + +/** + * struct ec_params_cec_read - Read a message from the CEC bus + * @port: CEC port to read a message on + */ +struct ec_params_cec_read { + uint8_t port; +} __ec_align1; + +/** + * struct ec_response_cec_read - Message read from the CEC bus + * @msg_len: length of msg in bytes + * @msg: message content read from the CEC bus + */ +struct ec_response_cec_read { + uint8_t msg_len; + uint8_t msg[MAX_CEC_MSG_LEN]; +} __ec_align1; + /* Set various CEC parameters */ #define EC_CMD_CEC_SET 0x00BA @@ -4529,6 +4550,8 @@ enum mkbp_cec_event { EC_MKBP_CEC_SEND_OK = BIT(0), /* Outgoing message was not acknowledged */ EC_MKBP_CEC_SEND_FAILED = BIT(1), + /* Incoming message can be read out by AP */ + EC_MKBP_CEC_HAVE_DATA = BIT(2), }; /*****************************************************************************/ -- GitLab From e7885b9c6564dc39b55f546b4a4afa0a44bb0be5 Mon Sep 17 00:00:00 2001 From: Reka Norman Date: Fri, 25 Aug 2023 12:44:00 +1000 Subject: [PATCH 0193/1451] media: cros-ec-cec: Allow specifying multiple HDMI connectors Update the cec_dmi_match_table to allow specifying multiple HDMI connectors for each device. Signed-off-by: Reka Norman Signed-off-by: Hans Verkuil --- .../media/cec/platform/cros-ec/cros-ec-cec.c | 49 ++++++++++++------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index 6989e63c05bea..371699d599dea 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -284,38 +284,43 @@ static SIMPLE_DEV_PM_OPS(cros_ec_cec_pm_ops, #if IS_ENABLED(CONFIG_PCI) && IS_ENABLED(CONFIG_DMI) /* - * The Firmware only handles a single CEC interface tied to a single HDMI - * connector we specify along with the DRM device name handling the HDMI output + * Specify the DRM device name handling the HDMI output and the HDMI connector + * corresponding to each CEC port. The order of connectors must match the order + * in the EC (first connector is EC port 0, ...), and the number of connectors + * must match the number of ports in the EC (which can be queried using the + * EC_CMD_CEC_PORT_COUNT host command). */ struct cec_dmi_match { const char *sys_vendor; const char *product_name; const char *devname; - const char *conn; + const char *const *conns; }; +static const char *const fizz_conns[] = { "Port B", NULL }; + static const struct cec_dmi_match cec_dmi_match_table[] = { /* Google Fizz */ - { "Google", "Fizz", "0000:00:02.0", "Port B" }, + { "Google", "Fizz", "0000:00:02.0", fizz_conns }, /* Google Brask */ - { "Google", "Brask", "0000:00:02.0", "Port B" }, + { "Google", "Brask", "0000:00:02.0", fizz_conns }, /* Google Moli */ - { "Google", "Moli", "0000:00:02.0", "Port B" }, + { "Google", "Moli", "0000:00:02.0", fizz_conns }, /* Google Kinox */ - { "Google", "Kinox", "0000:00:02.0", "Port B" }, + { "Google", "Kinox", "0000:00:02.0", fizz_conns }, /* Google Kuldax */ - { "Google", "Kuldax", "0000:00:02.0", "Port B" }, + { "Google", "Kuldax", "0000:00:02.0", fizz_conns }, /* Google Aurash */ - { "Google", "Aurash", "0000:00:02.0", "Port B" }, + { "Google", "Aurash", "0000:00:02.0", fizz_conns }, /* Google Gladios */ - { "Google", "Gladios", "0000:00:02.0", "Port B" }, + { "Google", "Gladios", "0000:00:02.0", fizz_conns }, /* Google Lisbon */ - { "Google", "Lisbon", "0000:00:02.0", "Port B" }, + { "Google", "Lisbon", "0000:00:02.0", fizz_conns }, }; static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, - const char **conn) + const char * const **conns) { int i; @@ -332,7 +337,7 @@ static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, if (!d) return ERR_PTR(-EPROBE_DEFER); put_device(d); - *conn = m->conn; + *conns = m->conns; return d; } } @@ -346,7 +351,7 @@ static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, #else static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, - const char **conn) + const char * const **conns) { return ERR_PTR(-ENODEV); } @@ -388,7 +393,7 @@ static int cros_ec_cec_get_write_cmd_version(struct cros_ec_cec *cros_ec_cec) static int cros_ec_cec_init_port(struct device *dev, struct cros_ec_cec *cros_ec_cec, int port_num, struct device *hdmi_dev, - const char *conn) + const char * const *conns) { struct cros_ec_cec_port *port; int ret; @@ -406,7 +411,13 @@ static int cros_ec_cec_init_port(struct device *dev, if (IS_ERR(port->adap)) return PTR_ERR(port->adap); - port->notify = cec_notifier_cec_adap_register(hdmi_dev, conn, + if (!conns[port_num]) { + dev_err(dev, "no conn for port %d\n", port_num); + ret = -ENODEV; + goto out_probe_adapter; + } + + port->notify = cec_notifier_cec_adap_register(hdmi_dev, conns[port_num], port->adap); if (!port->notify) { ret = -ENOMEM; @@ -435,10 +446,10 @@ static int cros_ec_cec_probe(struct platform_device *pdev) struct cros_ec_cec *cros_ec_cec; struct cros_ec_cec_port *port; struct device *hdmi_dev; - const char *conn = NULL; + const char * const *conns = NULL; int ret; - hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conn); + hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conns); if (IS_ERR(hdmi_dev)) return PTR_ERR(hdmi_dev); @@ -460,7 +471,7 @@ static int cros_ec_cec_probe(struct platform_device *pdev) for (int i = 0; i < cros_ec_cec->num_ports; i++) { ret = cros_ec_cec_init_port(&pdev->dev, cros_ec_cec, i, - hdmi_dev, conn); + hdmi_dev, conns); if (ret) goto unregister_ports; } -- GitLab From 5d227f02ceb9cc120cf04efbd77e12da182a5f62 Mon Sep 17 00:00:00 2001 From: Reka Norman Date: Fri, 25 Aug 2023 12:44:01 +1000 Subject: [PATCH 0194/1451] media: cros-ec-cec: Get number of CEC ports from EC Add a new CEC port count host command and use it to query the number of CEC ports from the EC. If the host command is not supported then it must be old EC firmware which only supports one port, so fall back to assuming one port. This patch completes support for multiple ports in cros-ec-cec. Signed-off-by: Reka Norman Signed-off-by: Hans Verkuil --- .../media/cec/platform/cros-ec/cros-ec-cec.c | 40 ++++++++++++++++--- .../linux/platform_data/cros_ec_commands.h | 11 +++++ 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index 371699d599dea..993deb85d3e28 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -21,10 +21,6 @@ #define DRV_NAME "cros-ec-cec" -/* Only one port is supported for now */ -#define CEC_NUM_PORTS 1 -#define CEC_PORT 0 - /** * struct cros_ec_cec_port - Driver data for a single EC CEC port * @@ -358,6 +354,38 @@ static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, #endif +static int cros_ec_cec_get_num_ports(struct cros_ec_cec *cros_ec_cec) +{ + struct ec_response_cec_port_count response; + int ret; + + ret = cros_ec_cmd(cros_ec_cec->cros_ec, 0, EC_CMD_CEC_PORT_COUNT, NULL, + 0, &response, sizeof(response)); + if (ret < 0) { + /* + * Old EC firmware only supports one port and does not support + * the port count command, so fall back to assuming one port. + */ + cros_ec_cec->num_ports = 1; + return 0; + } + + if (response.port_count == 0) { + dev_err(cros_ec_cec->cros_ec->dev, + "EC reports 0 CEC ports\n"); + return -ENODEV; + } + + if (response.port_count > EC_CEC_MAX_PORTS) { + dev_err(cros_ec_cec->cros_ec->dev, + "EC reports too many ports: %d\n", response.port_count); + return -EINVAL; + } + + cros_ec_cec->num_ports = response.port_count; + return 0; +} + static int cros_ec_cec_get_write_cmd_version(struct cros_ec_cec *cros_ec_cec) { struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; @@ -463,7 +491,9 @@ static int cros_ec_cec_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); - cros_ec_cec->num_ports = CEC_NUM_PORTS; + ret = cros_ec_cec_get_num_ports(cros_ec_cec); + if (ret) + return ret; ret = cros_ec_cec_get_write_cmd_version(cros_ec_cec); if (ret) diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index ad61c7ff0b285..7dae17b62a4d3 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -4536,6 +4536,17 @@ struct ec_response_cec_get { uint8_t val; } __ec_align1; +/* Get the number of CEC ports */ +#define EC_CMD_CEC_PORT_COUNT 0x00C1 + +/** + * struct ec_response_cec_port_count - CEC port count response + * @port_count: number of CEC ports + */ +struct ec_response_cec_port_count { + uint8_t port_count; +} __ec_align1; + /* CEC parameters command */ enum cec_command { /* CEC reading, writing and events enable */ -- GitLab From 8d3e6030e30fd1f2fad74265219f4ba39170a4ba Mon Sep 17 00:00:00 2001 From: Reka Norman Date: Fri, 25 Aug 2023 12:44:02 +1000 Subject: [PATCH 0195/1451] media: cros-ec-cec: Add Dibbi to the match table Dibbi has two HDMI ports which support CEC: Port D is EC port 0 Port B is EC port 1 Signed-off-by: Reka Norman Signed-off-by: Hans Verkuil --- drivers/media/cec/platform/cros-ec/cros-ec-cec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index 993deb85d3e28..21361eff50ff5 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -295,6 +295,7 @@ struct cec_dmi_match { }; static const char *const fizz_conns[] = { "Port B", NULL }; +static const char *const dibbi_conns[] = { "Port D", "Port B", NULL }; static const struct cec_dmi_match cec_dmi_match_table[] = { /* Google Fizz */ @@ -313,6 +314,8 @@ static const struct cec_dmi_match cec_dmi_match_table[] = { { "Google", "Gladios", "0000:00:02.0", fizz_conns }, /* Google Lisbon */ { "Google", "Lisbon", "0000:00:02.0", fizz_conns }, + /* Google Dibbi */ + { "Google", "Dibbi", "0000:00:02.0", dibbi_conns }, }; static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, -- GitLab From 5bc2de5f517d561a5b8dc472d3ba17d0f32b122e Mon Sep 17 00:00:00 2001 From: Stefan Adolfsson Date: Wed, 16 Aug 2023 12:41:25 +0200 Subject: [PATCH 0196/1451] media: cros-ec-cec: Add Constitution to the match table Constitution has two HDMI ports which support CEC: Port B is EC port 0 Port A is EC port 1 This patch depends on "media: cros-ec-cec: Add Dibbi to the match table". Signed-off-by: Stefan Adolfsson Reviewed-by: Guenter Roeck Signed-off-by: Hans Verkuil [hverkuil: updated to the new multi-port datastructures] --- drivers/media/cec/platform/cros-ec/cros-ec-cec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index 21361eff50ff5..85431af652240 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -296,6 +296,7 @@ struct cec_dmi_match { static const char *const fizz_conns[] = { "Port B", NULL }; static const char *const dibbi_conns[] = { "Port D", "Port B", NULL }; +static const char *const constitution_conns[] = { "Port B", "Port A", NULL }; static const struct cec_dmi_match cec_dmi_match_table[] = { /* Google Fizz */ @@ -316,6 +317,8 @@ static const struct cec_dmi_match cec_dmi_match_table[] = { { "Google", "Lisbon", "0000:00:02.0", fizz_conns }, /* Google Dibbi */ { "Google", "Dibbi", "0000:00:02.0", dibbi_conns }, + /* Google Constitution */ + { "Google", "Constitution", "0000:00:02.0", constitution_conns }, }; static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, -- GitLab From beeefd75fa35bc037bff10fc4f65434eb4429750 Mon Sep 17 00:00:00 2001 From: "rasheed.hsueh" Date: Fri, 18 Aug 2023 10:58:48 +0800 Subject: [PATCH 0197/1451] media: platform: cros-ec: Add Boxy to the match table The Google Boxy device uses the same approach as the Google Brask which enables the HDMI CEC via the cros-ec-cec driver. Signed-off-by: rasheed.hsueh Signed-off-by: Hans Verkuil [hverkuil: updated to the new multi-port datastructures] --- drivers/media/cec/platform/cros-ec/cros-ec-cec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index 85431af652240..920aed0d19295 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -297,6 +297,7 @@ struct cec_dmi_match { static const char *const fizz_conns[] = { "Port B", NULL }; static const char *const dibbi_conns[] = { "Port D", "Port B", NULL }; static const char *const constitution_conns[] = { "Port B", "Port A", NULL }; +static const char *const boxy_conns[] = { "Port D", NULL }; static const struct cec_dmi_match cec_dmi_match_table[] = { /* Google Fizz */ @@ -319,6 +320,8 @@ static const struct cec_dmi_match cec_dmi_match_table[] = { { "Google", "Dibbi", "0000:00:02.0", dibbi_conns }, /* Google Constitution */ { "Google", "Constitution", "0000:00:02.0", constitution_conns }, + /* Google Boxy */ + { "Google", "Boxy", "0000:00:02.0", boxy_conns }, }; static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, -- GitLab From e50f23b1ca240ec2ba9d6d3f17eb936d484e9888 Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Fri, 4 Aug 2023 14:55:21 +0800 Subject: [PATCH 0198/1451] media: dvb-frontends: drx39xyj: Remove unnecessary ternary operators There are a few ternary operators, the true or false judgement of which is unnecessary in C language semantics. Signed-off-by: Ruan Jinjie Signed-off-by: Hans Verkuil --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index a738573c8cd7a..19d8de400a687 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -4779,8 +4779,8 @@ set_frequency(struct drx_demod_instance *demod, bool image_to_select; s32 fm_frequency_shift = 0; - rf_mirror = (ext_attr->mirror == DRX_MIRROR_YES) ? true : false; - tuner_mirror = demod->my_common_attr->mirror_freq_spect ? false : true; + rf_mirror = ext_attr->mirror == DRX_MIRROR_YES; + tuner_mirror = !demod->my_common_attr->mirror_freq_spect; /* Program frequency shifter No need to account for mirroring on RF @@ -8765,7 +8765,7 @@ static int qam_flip_spec(struct drx_demod_instance *demod, struct drx_channel *c goto rw_error; } ext_attr->iqm_fs_rate_ofs = iqm_fs_rate_ofs; - ext_attr->pos_image = (ext_attr->pos_image) ? false : true; + ext_attr->pos_image = !ext_attr->pos_image; /* freeze dq/fq updating */ rc = drxj_dap_read_reg16(dev_addr, QAM_DQ_MODE__A, &data, 0); -- GitLab From e0878c7f7f2139ece5563d194872ba84d7e2f4bf Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Fri, 4 Aug 2023 14:55:22 +0800 Subject: [PATCH 0199/1451] media: radio-wl1273: Remove an unnecessary ternary operator There is a ternary operator, the true or false judgement of which is unnecessary in C language semantics. Signed-off-by: Ruan Jinjie Signed-off-by: Hans Verkuil --- drivers/media/radio/radio-wl1273.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index e8166eac9efe8..f6b98c304b72c 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -1020,7 +1020,7 @@ static int wl1273_fm_set_rds(struct wl1273_device *radio, unsigned int new_mode) } if (!r) - radio->rds_on = (new_mode == WL1273_RDS_ON) ? true : false; + radio->rds_on = new_mode == WL1273_RDS_ON; return r; } -- GitLab From e2f01278781f80ccb329218793d78980cdd8d3c3 Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Fri, 4 Aug 2023 14:55:23 +0800 Subject: [PATCH 0200/1451] media: dvb-usb: gp8psk: Remove an unnecessary ternary operator There is a ternary operator, the true or false judgement of which is unnecessary in C language semantics. Signed-off-by: Ruan Jinjie Signed-off-by: Hans Verkuil --- drivers/media/usb/dvb-usb/gp8psk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/dvb-usb/gp8psk.c b/drivers/media/usb/dvb-usb/gp8psk.c index b2b27a86dfe52..4cd21bb8805ed 100644 --- a/drivers/media/usb/dvb-usb/gp8psk.c +++ b/drivers/media/usb/dvb-usb/gp8psk.c @@ -287,7 +287,7 @@ static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap) int id = le16_to_cpu(d->udev->descriptor.idProduct); int is_rev1; - is_rev1 = (id == USB_PID_GENPIX_8PSK_REV_1_WARM) ? true : false; + is_rev1 = id == USB_PID_GENPIX_8PSK_REV_1_WARM; adap->fe_adap[0].fe = dvb_attach(gp8psk_fe_attach, &gp8psk_fe_ops, d, is_rev1); -- GitLab From 16fae979ed6b2753c07bdc9943cd9892349b69d4 Mon Sep 17 00:00:00 2001 From: Chen Jiahao Date: Wed, 16 Aug 2023 10:23:23 +0800 Subject: [PATCH 0201/1451] media: usb: siano: Use kmemdup to simplify kmalloc and memcpy logic Using kmemdup() helper function rather than implementing it again with kmalloc() + memcpy(), which improves the code readability. Signed-off-by: Chen Jiahao Reviewed-by: Dongliang Mu Signed-off-by: Hans Verkuil --- drivers/media/usb/siano/smsusb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index 8a39cac76c585..9d9e14c858e67 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -279,10 +279,8 @@ static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id) } } - fw_buffer = kmalloc(fw->size, GFP_KERNEL); + fw_buffer = kmemdup(fw->data, fw->size, GFP_KERNEL); if (fw_buffer) { - memcpy(fw_buffer, fw->data, fw->size); - rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2), fw_buffer, fw->size, &dummy, 1000); -- GitLab From a805136eec48c7f0e3b7dad44ec5efb506a938d8 Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Fri, 18 Aug 2023 18:15:40 +0800 Subject: [PATCH 0202/1451] media: c8sectpfe: Use the devm_clk_get_enabled() helper function With devm_clk_get_enabled() the call to clk_disable_unprepare() can be dropped from the error path and the remove callback. Signed-off-by: Ruan Jinjie Reviewed-by: Patrice Chotard Signed-off-by: Hans Verkuil --- .../st/sti/c8sectpfe/c8sectpfe-core.c | 26 +++++-------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c index 5dc1f908b49bd..e4cf27b5a0727 100644 --- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c @@ -695,16 +695,10 @@ static int c8sectpfe_probe(struct platform_device *pdev) platform_set_drvdata(pdev, fei); - fei->c8sectpfeclk = devm_clk_get(dev, "c8sectpfe"); + fei->c8sectpfeclk = devm_clk_get_enabled(dev, "c8sectpfe"); if (IS_ERR(fei->c8sectpfeclk)) { - dev_err(dev, "c8sectpfe clk not found\n"); - return PTR_ERR(fei->c8sectpfeclk); - } - - ret = clk_prepare_enable(fei->c8sectpfeclk); - if (ret) { dev_err(dev, "Failed to enable c8sectpfe clock\n"); - return ret; + return PTR_ERR(fei->c8sectpfeclk); } /* to save power disable all IP's (on by default) */ @@ -722,7 +716,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) 0, "c8sectpfe-idle-irq", fei); if (ret) { dev_err(dev, "Can't register c8sectpfe-idle-irq IRQ.\n"); - goto err_clk_disable; + return ret; } ret = devm_request_irq(dev, fei->error_irq, @@ -730,7 +724,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) "c8sectpfe-error-irq", fei); if (ret) { dev_err(dev, "Can't register c8sectpfe-error-irq IRQ.\n"); - goto err_clk_disable; + return ret; } fei->tsin_count = of_get_child_count(np); @@ -739,16 +733,14 @@ static int c8sectpfe_probe(struct platform_device *pdev) fei->tsin_count > fei->hw_stats.num_ib) { dev_err(dev, "More tsin declared than exist on SoC!\n"); - ret = -EINVAL; - goto err_clk_disable; + return -EINVAL; } fei->pinctrl = devm_pinctrl_get(dev); if (IS_ERR(fei->pinctrl)) { dev_err(dev, "Error getting tsin pins\n"); - ret = PTR_ERR(fei->pinctrl); - goto err_clk_disable; + return PTR_ERR(fei->pinctrl); } for_each_child_of_node(np, child) { @@ -859,7 +851,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) if (ret) { dev_err(dev, "c8sectpfe_tuner_register_frontend failed (%d)\n", ret); - goto err_clk_disable; + return ret; } c8sectpfe_debugfs_init(fei); @@ -868,8 +860,6 @@ static int c8sectpfe_probe(struct platform_device *pdev) err_node_put: of_node_put(child); -err_clk_disable: - clk_disable_unprepare(fei->c8sectpfeclk); return ret; } @@ -903,8 +893,6 @@ static void c8sectpfe_remove(struct platform_device *pdev) if (readl(fei->io + SYS_OTHER_CLKEN)) writel(0, fei->io + SYS_OTHER_CLKEN); - - clk_disable_unprepare(fei->c8sectpfeclk); } -- GitLab From 1c2786632e20c8f0fd4004fae3b3490276e5e5da Mon Sep 17 00:00:00 2001 From: Ming Qian Date: Tue, 22 Aug 2023 09:45:06 +0800 Subject: [PATCH 0203/1451] media: imx-jpeg: initiate a drain of the capture queue in dynamic resolution change The last buffer from before the change must be marked, with the V4L2_BUF_FLAG_LAST flag, similarly to the Drain sequence above. Meanwhile if V4L2_DEC_CMD_STOP is sent before the source change triggered, we need to restore the is_draing flag after the draining in dynamic resolution change. Fixes: b4e1fb8643da ("media: imx-jpeg: Support dynamic resolution change") Signed-off-by: Ming Qian Reviewed-by: Nicolas Dufresne Signed-off-by: Hans Verkuil --- .../media/platform/nxp/imx-jpeg/mxc-jpeg.c | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index b7a720198ce57..e74b0ed8ec5ba 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -1322,6 +1322,20 @@ static bool mxc_jpeg_compare_format(const struct mxc_jpeg_fmt *fmt1, return false; } +static void mxc_jpeg_set_last_buffer(struct mxc_jpeg_ctx *ctx) +{ + struct vb2_v4l2_buffer *next_dst_buf; + + next_dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (!next_dst_buf) { + ctx->fh.m2m_ctx->is_draining = true; + ctx->fh.m2m_ctx->next_buf_last = true; + return; + } + + v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, next_dst_buf); +} + static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx, struct mxc_jpeg_src_buf *jpeg_src_buf) { @@ -1378,6 +1392,8 @@ static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx, mxc_jpeg_sizeimage(q_data_cap); notify_src_chg(ctx); ctx->source_change = 1; + if (vb2_is_streaming(v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx))) + mxc_jpeg_set_last_buffer(ctx); } return ctx->source_change ? true : false; @@ -1638,8 +1654,13 @@ static void mxc_jpeg_stop_streaming(struct vb2_queue *q) v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); } - if (V4L2_TYPE_IS_OUTPUT(q->type) || !ctx->source_change) - v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q); + v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q); + /* if V4L2_DEC_CMD_STOP is sent before the source change triggered, + * restore the is_draining flag + */ + if (V4L2_TYPE_IS_CAPTURE(q->type) && ctx->source_change && ctx->fh.m2m_ctx->last_src_buf) + ctx->fh.m2m_ctx->is_draining = true; + if (V4L2_TYPE_IS_OUTPUT(q->type) && v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) { notify_eos(ctx); @@ -1916,7 +1937,7 @@ static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb) return -EINVAL; for (i = 0; i < q_data->fmt->mem_planes; i++) { sizeimage = mxc_jpeg_get_plane_size(q_data, i); - if (vb2_plane_size(vb, i) < sizeimage) { + if (!ctx->source_change && vb2_plane_size(vb, i) < sizeimage) { dev_err(dev, "plane %d too small (%lu < %lu)", i, vb2_plane_size(vb, i), sizeimage); return -EINVAL; -- GitLab From 0c7af09408b3e4bb7e9a3b430a93473494d9b748 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Wed, 23 Aug 2023 15:16:52 +0800 Subject: [PATCH 0204/1451] media: cobalt: Use list_for_each_entry() helper Convert list_for_each() to list_for_each_entry() so that the p list_head pointer and list_entry() call are no longer needed, which can reduce a few lines of code. No functional changed. Signed-off-by: Jinjie Ruan Signed-off-by: Hans Verkuil --- drivers/media/pci/cobalt/cobalt-v4l2.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c index 4bfbcca14f60b..26bf58d17a3df 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.c +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -107,11 +107,9 @@ static void chain_all_buffers(struct cobalt_stream *s) { struct sg_dma_desc_info *desc[NR_BUFS]; struct cobalt_buffer *cb; - struct list_head *p; int i = 0; - list_for_each(p, &s->bufs) { - cb = list_entry(p, struct cobalt_buffer, list); + list_for_each_entry(cb, &s->bufs, list) { desc[i] = &s->dma_desc_info[cb->vb.vb2_buf.index]; if (i > 0) descriptor_list_chain(desc[i-1], desc[i]); @@ -348,7 +346,6 @@ static void cobalt_dma_stop_streaming(struct cobalt_stream *s) struct cobalt *cobalt = s->cobalt; struct sg_dma_desc_info *desc; struct cobalt_buffer *cb; - struct list_head *p; unsigned long flags; int timeout_msec = 100; int rx = s->video_channel; @@ -367,8 +364,7 @@ static void cobalt_dma_stop_streaming(struct cobalt_stream *s) /* Try to stop the DMA engine gracefully */ spin_lock_irqsave(&s->irqlock, flags); - list_for_each(p, &s->bufs) { - cb = list_entry(p, struct cobalt_buffer, list); + list_for_each_entry(cb, &s->bufs, list) { desc = &s->dma_desc_info[cb->vb.vb2_buf.index]; /* Stop DMA after this descriptor chain */ descriptor_list_end_of_chain(desc); -- GitLab From 88d4b23a629ebd34f682f770cb6c2116c851f7b8 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 24 Aug 2023 03:38:58 +0200 Subject: [PATCH 0205/1451] media: hantro: Check whether reset op is defined before use The i.MX8MM/N/P does not define the .reset op since reset of the VPU is done by genpd. Check whether the .reset op is defined before calling it to avoid NULL pointer dereference. Note that the Fixes tag is set to the commit which removed the reset op from i.MX8M Hantro G2 implementation, this is because before this commit all the implementations did define the .reset op. Fixes: 6971efb70ac3 ("media: hantro: Allow i.MX8MQ G1 and G2 to run independently") Signed-off-by: Marek Vasut Reviewed-by: Chen-Yu Tsai Tested-by: Chen-Yu Tsai Reviewed-by: Adam Ford Signed-off-by: Hans Verkuil --- drivers/media/platform/verisilicon/hantro_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index 423fc85d79ee3..50ec24c753e9e 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -125,7 +125,8 @@ void hantro_watchdog(struct work_struct *work) ctx = v4l2_m2m_get_curr_priv(vpu->m2m_dev); if (ctx) { vpu_err("frame processing timed out!\n"); - ctx->codec_ops->reset(ctx); + if (ctx->codec_ops->reset) + ctx->codec_ops->reset(ctx); hantro_job_finish(vpu, ctx, VB2_BUF_STATE_ERROR); } } -- GitLab From 6e481d52d363218a3e6feb31694da74b38b30fad Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 24 Aug 2023 03:39:35 +0200 Subject: [PATCH 0206/1451] media: verisilicon: Do not enable G2 postproc downscale if source is narrower than destination In case of encoded input VP9 data width that is not multiple of macroblock size, which is 16 (e.g. 1080x1920 frames, where 1080 is multiple of 8), the width is padded to be a multiple of macroblock size (for 1080x1920 frames, that is 1088x1920). The hantro_postproc_g2_enable() checks whether the encoded data width is equal to decoded frame width, and if not, enables down-scale mode. For a frame where input is 1080x1920 and output is 1088x1920, this is incorrect as no down-scale happens, the frame is only padded. Enabling the down-scale mode in this case results in corrupted frames. Fix this by adjusting the check to test whether encoded data width is greater than decoded frame width, and only in that case enable the down-scale mode. To generate input test data to trigger this bug, use e.g.: $ gst-launch-1.0 videotestsrc ! video/x-raw,width=272,height=256,format=I420 ! \ vp9enc ! matroskamux ! filesink location=/tmp/test.vp9 To trigger the bug upon decoding (note that the NV12 must be forced, as that assures the output data would pass the G2 postproc): $ gst-launch-1.0 filesrc location=/tmp/test.vp9 ! matroskademux ! vp9parse ! \ v4l2slvp9dec ! video/x-raw,format=NV12 ! videoconvert ! fbdevsink Fixes: 79c987de8b35 ("media: hantro: Use post processor scaling capacities") Signed-off-by: Marek Vasut Reviewed-by: Benjamin Gaignard Signed-off-by: Hans Verkuil --- drivers/media/platform/verisilicon/hantro_postproc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/verisilicon/hantro_postproc.c b/drivers/media/platform/verisilicon/hantro_postproc.c index 0224ff68ab3fc..64d6fb852ae9b 100644 --- a/drivers/media/platform/verisilicon/hantro_postproc.c +++ b/drivers/media/platform/verisilicon/hantro_postproc.c @@ -107,7 +107,7 @@ static void hantro_postproc_g1_enable(struct hantro_ctx *ctx) static int down_scale_factor(struct hantro_ctx *ctx) { - if (ctx->src_fmt.width == ctx->dst_fmt.width) + if (ctx->src_fmt.width <= ctx->dst_fmt.width) return 0; return DIV_ROUND_CLOSEST(ctx->src_fmt.width, ctx->dst_fmt.width); -- GitLab From 099be1822d1f095433f4b08af9cc9d6308ec1953 Mon Sep 17 00:00:00 2001 From: Rajeshwar R Shinde Date: Wed, 30 Aug 2023 13:14:01 +0530 Subject: [PATCH 0207/1451] media: gspca: cpia1: shift-out-of-bounds in set_flicker Syzkaller reported the following issue: UBSAN: shift-out-of-bounds in drivers/media/usb/gspca/cpia1.c:1031:27 shift exponent 245 is too large for 32-bit type 'int' When the value of the variable "sd->params.exposure.gain" exceeds the number of bits in an integer, a shift-out-of-bounds error is reported. It is triggered because the variable "currentexp" cannot be left-shifted by more than the number of bits in an integer. In order to avoid invalid range during left-shift, the conditional expression is added. Reported-by: syzbot+e27f3dbdab04e43b9f73@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/20230818164522.12806-1-coolrrsh@gmail.com Link: https://syzkaller.appspot.com/bug?extid=e27f3dbdab04e43b9f73 Signed-off-by: Rajeshwar R Shinde Signed-off-by: Hans Verkuil --- drivers/media/usb/gspca/cpia1.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/usb/gspca/cpia1.c b/drivers/media/usb/gspca/cpia1.c index 46ed95483e222..5f5fa851ca640 100644 --- a/drivers/media/usb/gspca/cpia1.c +++ b/drivers/media/usb/gspca/cpia1.c @@ -18,6 +18,7 @@ #include #include +#include #include "gspca.h" @@ -1028,6 +1029,8 @@ static int set_flicker(struct gspca_dev *gspca_dev, int on, int apply) sd->params.exposure.expMode = 2; sd->exposure_status = EXPOSURE_NORMAL; } + if (sd->params.exposure.gain >= BITS_PER_TYPE(currentexp)) + return -EINVAL; currentexp = currentexp << sd->params.exposure.gain; sd->params.exposure.gain = 0; /* round down current exposure to nearest value */ -- GitLab From 05b34200a1552d39f2369052ce94d9563a5f15c0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 30 Aug 2023 14:31:40 +0200 Subject: [PATCH 0208/1451] media: videobuf2: fix typo: vb2_dbuf -> vb2_qbuf Fix a small typo in the debug message: vb2_dbuf -> vb2_qbuf Signed-off-by: Hans Verkuil Reviewed-by: Andrzej Pietrasiewicz --- drivers/media/common/videobuf2/videobuf2-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index cf6727d9c81f3..27aee92f3eea4 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -2890,7 +2890,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ if (copy_timestamp) b->timestamp = ktime_get_ns(); ret = vb2_core_qbuf(q, index, NULL, NULL); - dprintk(q, 5, "vb2_dbuf result: %d\n", ret); + dprintk(q, 5, "vb2_qbuf result: %d\n", ret); if (ret) return ret; -- GitLab From e85322573d986f0cd069eb8b639955d21d90db44 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Sun, 3 Sep 2023 16:14:39 +0800 Subject: [PATCH 0209/1451] media: cx231xx: Switch to use kmemdup() helper Use kmemdup() helper instead of open-coding to simplify the code. Signed-off-by: Jinjie Ruan Signed-off-by: Hans Verkuil --- drivers/media/usb/cx231xx/cx231xx-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index 727e6268567f7..746727ea1a4c7 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c @@ -751,10 +751,9 @@ int cx231xx_ep5_bulkout(struct cx231xx *dev, u8 *firmware, u16 size) int ret = -ENOMEM; u32 *buffer; - buffer = kzalloc(4096, GFP_KERNEL); + buffer = kmemdup(firmware, 4096, GFP_KERNEL); if (buffer == NULL) return -ENOMEM; - memcpy(&buffer[0], firmware, 4096); ret = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 5), buffer, 4096, &actlen, 2000); -- GitLab From 2b651ba688b3d0dbfc35701a12d6eb4885800e14 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Sun, 3 Sep 2023 16:14:40 +0800 Subject: [PATCH 0210/1451] media: cx231xx: Add EP5_BUF_SIZE and EP5_TIMEOUT_MS macros Define EP5_BUF_SIZE and EP5_TIMEOUT_MS macros to make the code more readable. Signed-off-by: Jinjie Ruan Suggested-by: Andrzej Pietrasiewicz Signed-off-by: Hans Verkuil --- drivers/media/usb/cx231xx/cx231xx-core.c | 4 ++-- drivers/media/usb/cx231xx/cx231xx.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index 746727ea1a4c7..57a8b4780a7d6 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c @@ -751,12 +751,12 @@ int cx231xx_ep5_bulkout(struct cx231xx *dev, u8 *firmware, u16 size) int ret = -ENOMEM; u32 *buffer; - buffer = kmemdup(firmware, 4096, GFP_KERNEL); + buffer = kmemdup(firmware, EP5_BUF_SIZE, GFP_KERNEL); if (buffer == NULL) return -ENOMEM; ret = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 5), - buffer, 4096, &actlen, 2000); + buffer, EP5_BUF_SIZE, &actlen, EP5_TIMEOUT_MS); if (ret) dev_err(dev->dev, diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 6929e4d97067a..74339a6a2f718 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -120,6 +120,9 @@ #define CX23417_OSC_EN 8 #define CX23417_RESET 9 +#define EP5_BUF_SIZE 4096 +#define EP5_TIMEOUT_MS 2000 + struct cx23417_fmt { u32 fourcc; /* v4l2 format id */ int depth; -- GitLab From e986ab55e7576053a6a764ec71e0517245eae758 Mon Sep 17 00:00:00 2001 From: Mikhail Rudenko Date: Thu, 3 Aug 2023 15:37:42 +0300 Subject: [PATCH 0211/1451] MAINTAINERS: fix file path for Omnvision OV4689 Correct the driver source path specified in the MAINTAINERS file, which was mistakenly set due to an oversight during the driver's initial addition. Signed-off-by: Mikhail Rudenko Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index b19995690904a..20e37b562c9ec 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15772,7 +15772,7 @@ L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/ovti,ov4689.yaml -F: drivers/media/i2c/ov5647.c +F: drivers/media/i2c/ov4689.c OMNIVISION OV5640 SENSOR DRIVER M: Steve Longerbeam -- GitLab From d66b45e1b082462c3e14528b83e18ee92362e456 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 19 Jul 2023 13:16:10 +0300 Subject: [PATCH 0212/1451] media: ov13b10: Fix some error checking in probe The "ret = " assignment was missing, so ov13b10_power_on() is not checked for errors. Add the assignment. Fixes: 6e28afd15228 ("media: ov13b10: add PM control support based on power resources") Signed-off-by: Dan Carpenter Reviewed-by: Bingbu Cao Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov13b10.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov13b10.c b/drivers/media/i2c/ov13b10.c index dbc642c5995b6..8ebdb32dd3dbc 100644 --- a/drivers/media/i2c/ov13b10.c +++ b/drivers/media/i2c/ov13b10.c @@ -1501,7 +1501,7 @@ static int ov13b10_probe(struct i2c_client *client) full_power = acpi_dev_state_d0(&client->dev); if (full_power) { - ov13b10_power_on(&client->dev); + ret = ov13b10_power_on(&client->dev); if (ret) { dev_err(&client->dev, "failed to power on\n"); return ret; -- GitLab From 8fc29e3c9f682d4ad9b0764d44ecc6c19b000051 Mon Sep 17 00:00:00 2001 From: "Guoniu.zhou" Date: Wed, 19 Jul 2023 15:30:12 +0800 Subject: [PATCH 0213/1451] media: ov5640: fix vblank unchange issue when work at dvp mode The value of V4L2_CID_VBLANK control is initialized to default vblank value of 640x480 when driver probe. When OV5640 work at DVP mode, the control value won't update and lead to sensor can't output data if the resolution remain the same as last time since incorrect total vertical size. So update it when there is a new value applied. Fixes: bce93b827de6 ("media: ov5640: Add VBLANK control") Signed-off-by: Guoniu.zhou Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov5640.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 5fe85aa2d2ec4..1c9cda1e7df5c 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -2850,12 +2850,22 @@ static int ov5640_try_fmt_internal(struct v4l2_subdev *sd, return 0; } +static void __v4l2_ctrl_vblank_update(struct ov5640_dev *sensor, u32 vblank) +{ + const struct ov5640_mode_info *mode = sensor->current_mode; + + __v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV5640_MIN_VBLANK, + OV5640_MAX_VTS - mode->height, 1, vblank); + + __v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, vblank); +} + static int ov5640_update_pixel_rate(struct ov5640_dev *sensor) { const struct ov5640_mode_info *mode = sensor->current_mode; enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate; struct v4l2_mbus_framefmt *fmt = &sensor->fmt; - const struct ov5640_timings *timings; + const struct ov5640_timings *timings = ov5640_timings(sensor, mode); s32 exposure_val, exposure_max; unsigned int hblank; unsigned int i = 0; @@ -2874,6 +2884,8 @@ static int ov5640_update_pixel_rate(struct ov5640_dev *sensor) __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, ov5640_calc_pixel_rate(sensor)); + __v4l2_ctrl_vblank_update(sensor, timings->vblank_def); + return 0; } @@ -2916,15 +2928,12 @@ static int ov5640_update_pixel_rate(struct ov5640_dev *sensor) __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate); __v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i); - timings = ov5640_timings(sensor, mode); hblank = timings->htot - mode->width; __v4l2_ctrl_modify_range(sensor->ctrls.hblank, hblank, hblank, 1, hblank); vblank = timings->vblank_def; - __v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV5640_MIN_VBLANK, - OV5640_MAX_VTS - mode->height, 1, vblank); - __v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, vblank); + __v4l2_ctrl_vblank_update(sensor, vblank); exposure_max = timings->crop.height + vblank - 4; exposure_val = clamp_t(s32, sensor->ctrls.exposure->val, -- GitLab From b9a53a6975d9bcfb41950ed8566ae76ceb24d595 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 4 Aug 2023 09:23:22 +0300 Subject: [PATCH 0214/1451] media: ivsc: Improve Kconfig help text Improve the Kconfig help text to convey the ACE is for changing camera sensor ownership and CSI for configuring the CSI-2 rx and tx. Suggested-by: Laurent Pinchart Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/pci/intel/ivsc/Kconfig | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/media/pci/intel/ivsc/Kconfig b/drivers/media/pci/intel/ivsc/Kconfig index 212753450576a..0acea4678fc0d 100644 --- a/drivers/media/pci/intel/ivsc/Kconfig +++ b/drivers/media/pci/intel/ivsc/Kconfig @@ -10,6 +10,12 @@ config INTEL_VSC help This adds support for Intel Visual Sensing Controller (IVSC). - Enables the IVSC firmware services required for controlling - camera sensor ownership and CSI-2 link through Image Processing - Unit(IPU) driver of Intel. + The IVSC support is split into two devices, ACE (Algorithm + Context Engine) and CSI (Camera Serial Interface), each of which + have their own drivers. The ACE is used to select the ownership + of the sensor between the IVSC and the host CPU while the CSI is + used to both select the routing destination for the data the + sensor transmits over the CSI-2 bus between the IVSC and the + host CPU and to configure the CSI-2 bus itself. + + The modules will be called ivsc-ace and ivsc-csi. -- GitLab From 12ee5f71e0e7f93b10f83655c8c334c06536f9cb Mon Sep 17 00:00:00 2001 From: Tommaso Merciai Date: Mon, 31 Jul 2023 23:52:15 +0200 Subject: [PATCH 0215/1451] media: dt-bindings: ov5693: fix maintainer email address Switch my mail address from a company mail to a personal one. Signed-off-by: Tommaso Merciai Acked-by: Conor Dooley Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- Documentation/devicetree/bindings/media/i2c/ovti,ov5693.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov5693.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov5693.yaml index 6829a4aadd22e..3368b3bd8ef2f 100644 --- a/Documentation/devicetree/bindings/media/i2c/ovti,ov5693.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov5693.yaml @@ -8,7 +8,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Omnivision OV5693/OV5695 CMOS Sensors maintainers: - - Tommaso Merciai + - Tommaso Merciai description: | The Omnivision OV5693/OV5695 are high performance, 1/4-inch, 5 megapixel, CMOS -- GitLab From e2d3e77d0e7d3caf676cb0eb707f8c7b0a4d41b9 Mon Sep 17 00:00:00 2001 From: Jean-Michel Hautbois Date: Thu, 16 Sep 2021 19:25:04 +0200 Subject: [PATCH 0216/1451] media: staging: ipu3-imgu: Initialise height_per_slice in the stripes While playing with low resolutions for the grid, it appeared that height_per_slice is not initialised if we are not using both stripes for the calculations. This pattern occurs three times: - for the awb_fr processing block - for the af processing block - for the awb processing block The idea of this small portion of code is to reduce complexity in loading the statistics, it could be done also when only one stripe is used. Fix it by getting this initialisation code outside of the else() test case. Signed-off-by: Jean-Michel Hautbois Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/staging/media/ipu3/ipu3-css-params.c | 44 ++++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/staging/media/ipu3/ipu3-css-params.c b/drivers/staging/media/ipu3/ipu3-css-params.c index 76ad802d694e1..34f574b0b5216 100644 --- a/drivers/staging/media/ipu3/ipu3-css-params.c +++ b/drivers/staging/media/ipu3/ipu3-css-params.c @@ -2425,16 +2425,16 @@ int imgu_css_cfg_acc(struct imgu_css *css, unsigned int pipe, acc->awb_fr.stripes[1].grid_cfg.width, b_w_log2); acc->awb_fr.stripes[1].grid_cfg.x_end = end; - - /* - * To reduce complexity of debubbling and loading - * statistics fix grid_height_per_slice to 1 for both - * stripes. - */ - for (i = 0; i < stripes; i++) - acc->awb_fr.stripes[i].grid_cfg.height_per_slice = 1; } + /* + * To reduce complexity of debubbling and loading + * statistics fix grid_height_per_slice to 1 for both + * stripes. + */ + for (i = 0; i < stripes; i++) + acc->awb_fr.stripes[i].grid_cfg.height_per_slice = 1; + if (imgu_css_awb_fr_ops_calc(css, pipe, &acc->awb_fr)) return -EINVAL; @@ -2597,15 +2597,15 @@ int imgu_css_cfg_acc(struct imgu_css *css, unsigned int pipe, imgu_css_grid_end(acc->af.stripes[1].grid_cfg.x_start, acc->af.stripes[1].grid_cfg.width, b_w_log2); - - /* - * To reduce complexity of debubbling and loading statistics - * fix grid_height_per_slice to 1 for both stripes - */ - for (i = 0; i < stripes; i++) - acc->af.stripes[i].grid_cfg.height_per_slice = 1; } + /* + * To reduce complexity of debubbling and loading statistics + * fix grid_height_per_slice to 1 for both stripes + */ + for (i = 0; i < stripes; i++) + acc->af.stripes[i].grid_cfg.height_per_slice = 1; + if (imgu_css_af_ops_calc(css, pipe, &acc->af)) return -EINVAL; @@ -2677,15 +2677,15 @@ int imgu_css_cfg_acc(struct imgu_css *css, unsigned int pipe, imgu_css_grid_end(acc->awb.stripes[1].grid.x_start, acc->awb.stripes[1].grid.width, b_w_log2); - - /* - * To reduce complexity of debubbling and loading statistics - * fix grid_height_per_slice to 1 for both stripes - */ - for (i = 0; i < stripes; i++) - acc->awb.stripes[i].grid.height_per_slice = 1; } + /* + * To reduce complexity of debubbling and loading statistics + * fix grid_height_per_slice to 1 for both stripes + */ + for (i = 0; i < stripes; i++) + acc->awb.stripes[i].grid.height_per_slice = 1; + if (imgu_css_awb_ops_calc(css, pipe, &acc->awb)) return -EINVAL; -- GitLab From 17f2370a21e4a435768c4f81cc82779a2135bff7 Mon Sep 17 00:00:00 2001 From: Suhrid Subramaniam Date: Mon, 10 Jul 2023 18:31:40 -0700 Subject: [PATCH 0217/1451] media: v4l: Fix documentation for 12-bit packed Bayer Fix documentation for R13 and R33 low bits. Signed-off-by: Suhrid Subramaniam Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- Documentation/userspace-api/media/v4l/pixfmt-srggb12p.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/pixfmt-srggb12p.rst b/Documentation/userspace-api/media/v4l/pixfmt-srggb12p.rst index b6e79e2f8ce46..7c3810ff783c3 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-srggb12p.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-srggb12p.rst @@ -60,7 +60,7 @@ Each cell is one byte. G\ :sub:`10low`\ (bits 3--0) - G\ :sub:`12high` - R\ :sub:`13high` - - R\ :sub:`13low`\ (bits 3--2) + - R\ :sub:`13low`\ (bits 7--4) G\ :sub:`12low`\ (bits 3--0) - - start + 12: @@ -82,6 +82,6 @@ Each cell is one byte. G\ :sub:`30low`\ (bits 3--0) - G\ :sub:`32high` - R\ :sub:`33high` - - R\ :sub:`33low`\ (bits 3--2) + - R\ :sub:`33low`\ (bits 7--4) G\ :sub:`32low`\ (bits 3--0) -- GitLab From e9e2e88f3c16a7462420182afafb8d8783524ffd Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Fri, 18 Aug 2023 18:16:24 +0800 Subject: [PATCH 0218/1451] media: ov2640: Use the devm_clk_get_enabled() helper function With devm_clk_get_enabled() the call to clk_disable_unprepare() can be dropped from the error path and the remove callback. Signed-off-by: Ruan Jinjie Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov2640.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index bb6c9863a5460..2d08d30175c01 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -1205,17 +1205,14 @@ static int ov2640_probe(struct i2c_client *client) return -ENOMEM; if (client->dev.of_node) { - priv->clk = devm_clk_get(&client->dev, "xvclk"); + priv->clk = devm_clk_get_enabled(&client->dev, "xvclk"); if (IS_ERR(priv->clk)) return PTR_ERR(priv->clk); - ret = clk_prepare_enable(priv->clk); - if (ret) - return ret; } ret = ov2640_probe_dt(client, priv); if (ret) - goto err_clk; + return ret; priv->win = ov2640_select_win(SVGA_WIDTH, SVGA_HEIGHT); priv->cfmt_code = MEDIA_BUS_FMT_UYVY8_2X8; @@ -1264,8 +1261,6 @@ static int ov2640_probe(struct i2c_client *client) err_hdl: v4l2_ctrl_handler_free(&priv->hdl); mutex_destroy(&priv->lock); -err_clk: - clk_disable_unprepare(priv->clk); return ret; } @@ -1278,7 +1273,6 @@ static void ov2640_remove(struct i2c_client *client) mutex_destroy(&priv->lock); media_entity_cleanup(&priv->subdev.entity); v4l2_device_unregister_subdev(&priv->subdev); - clk_disable_unprepare(priv->clk); } static const struct i2c_device_id ov2640_id[] = { -- GitLab From b97213a41140b87f48865ba594a1f4b5c5566631 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 23 Aug 2023 12:03:42 +0300 Subject: [PATCH 0219/1451] media: v4l2-mc: Make v4l2_pipeline_pm_{get,put} deprecated The v4l2_pipeline_pm_get() and v4l2_pipeline_pm_put() functions were needed to control sub-devices' power states before runtime PM. These functions should no longer be used, and instead sub-device drivers should use runtime PM. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- include/media/v4l2-mc.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/media/v4l2-mc.h b/include/media/v4l2-mc.h index b39586dfba358..ed0a44b6eadae 100644 --- a/include/media/v4l2-mc.h +++ b/include/media/v4l2-mc.h @@ -143,6 +143,9 @@ int v4l2_create_fwnode_links(struct v4l2_subdev *src_sd, * v4l2_pipeline_pm_get - Increase the use count of a pipeline * @entity: The root entity of a pipeline * + * THIS FUNCTION IS DEPRECATED. DO NOT USE IN NEW DRIVERS. USE RUNTIME PM + * ON SUB-DEVICE DRIVERS INSTEAD. + * * Update the use count of all entities in the pipeline and power entities on. * * This function is intended to be called in video node open. It uses @@ -157,6 +160,9 @@ int v4l2_pipeline_pm_get(struct media_entity *entity); * v4l2_pipeline_pm_put - Decrease the use count of a pipeline * @entity: The root entity of a pipeline * + * THIS FUNCTION IS DEPRECATED. DO NOT USE IN NEW DRIVERS. USE RUNTIME PM + * ON SUB-DEVICE DRIVERS INSTEAD. + * * Update the use count of all entities in the pipeline and power entities off. * * This function is intended to be called in video node release. It uses -- GitLab From 18e35ba0d89f89bdda8001c6b34b18f62917d10d Mon Sep 17 00:00:00 2001 From: Wentong Wu Date: Tue, 29 Aug 2023 13:24:26 +0800 Subject: [PATCH 0220/1451] media: ivsc: csi: remove name identifier Remove name identifier to match the device with the defined UUID when load driver module. Signed-off-by: Wentong Wu Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/pci/intel/ivsc/mei_csi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/pci/intel/ivsc/mei_csi.c b/drivers/media/pci/intel/ivsc/mei_csi.c index 00ba611e0f68d..2a6b828fd8dd5 100644 --- a/drivers/media/pci/intel/ivsc/mei_csi.c +++ b/drivers/media/pci/intel/ivsc/mei_csi.c @@ -30,7 +30,6 @@ #include #include -#define MEI_CSI_DRIVER_NAME "ivsc_csi" #define MEI_CSI_ENTITY_NAME "Intel IVSC CSI" #define MEI_CSI_LINK_FREQ_400MHZ 400000000ULL @@ -804,14 +803,14 @@ static void mei_csi_remove(struct mei_cl_device *cldev) 0xAF, 0x93, 0x7b, 0x44, 0x53, 0xAC, 0x29, 0xDA) static const struct mei_cl_device_id mei_csi_tbl[] = { - { MEI_CSI_DRIVER_NAME, MEI_CSI_UUID, MEI_CL_VERSION_ANY }, + { .uuid = MEI_CSI_UUID, .version = MEI_CL_VERSION_ANY }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(mei, mei_csi_tbl); static struct mei_cl_driver mei_csi_driver = { .id_table = mei_csi_tbl, - .name = MEI_CSI_DRIVER_NAME, + .name = KBUILD_MODNAME, .probe = mei_csi_probe, .remove = mei_csi_remove, -- GitLab From 6b6f41791b443e9d141ae254ec0de833841497a9 Mon Sep 17 00:00:00 2001 From: Wentong Wu Date: Tue, 29 Aug 2023 13:24:27 +0800 Subject: [PATCH 0221/1451] media: ivsc: ace: remove name identifier Remove name identifier to match the device with the defined UUID when load driver module. Signed-off-by: Wentong Wu Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/pci/intel/ivsc/mei_ace.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/pci/intel/ivsc/mei_ace.c b/drivers/media/pci/intel/ivsc/mei_ace.c index a0491f3078311..d4ecc2b4a7f07 100644 --- a/drivers/media/pci/intel/ivsc/mei_ace.c +++ b/drivers/media/pci/intel/ivsc/mei_ace.c @@ -30,8 +30,6 @@ #include #include -#define MEI_ACE_DRIVER_NAME "ivsc_ace" - /* indicating driver message */ #define ACE_DRV_MSG 1 /* indicating set command */ @@ -554,14 +552,14 @@ static const struct dev_pm_ops mei_ace_pm_ops = { 0x9B, 0x78, 0x03, 0x61, 0x63, 0x5E, 0x24, 0x47) static const struct mei_cl_device_id mei_ace_tbl[] = { - { MEI_ACE_DRIVER_NAME, MEI_ACE_UUID, MEI_CL_VERSION_ANY }, + { .uuid = MEI_ACE_UUID, .version = MEI_CL_VERSION_ANY }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(mei, mei_ace_tbl); static struct mei_cl_driver mei_ace_driver = { .id_table = mei_ace_tbl, - .name = MEI_ACE_DRIVER_NAME, + .name = KBUILD_MODNAME, .probe = mei_ace_probe, .remove = mei_ace_remove, -- GitLab From 6966f2f7abbaf32fa395eff8e2888ea10d422e40 Mon Sep 17 00:00:00 2001 From: Wentong Wu Date: Tue, 29 Aug 2023 13:24:28 +0800 Subject: [PATCH 0222/1451] media: ivsc: ace: probe ace device after IPU bridge is initialized. During probe ivsc ace device, acpi_dev_clear_dependencies() will be called to clear the consumer and supplier relationship between camera sensor device and ivsc device. But IPU bridge will setup the connection swnodes for ivsc device and camera sensor device based on this consumer and supplier relationship. This patch defers ivsc ace's probe to make sure IPU bridge is initialized before this consumer and supplier relationship between camera sensor device and IVSC device is cleared. Signed-off-by: Wentong Wu Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/pci/intel/ivsc/mei_ace.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/pci/intel/ivsc/mei_ace.c b/drivers/media/pci/intel/ivsc/mei_ace.c index d4ecc2b4a7f07..3622271c71c88 100644 --- a/drivers/media/pci/intel/ivsc/mei_ace.c +++ b/drivers/media/pci/intel/ivsc/mei_ace.c @@ -406,6 +406,9 @@ static int mei_ace_setup_dev_link(struct mei_ace *ace) if (!csi_dev) { ret = -EPROBE_DEFER; goto err; + } else if (!dev_fwnode(csi_dev)) { + ret = -EPROBE_DEFER; + goto err_put; } /* setup link between mei_ace and mei_csi */ -- GitLab From 0822315e46b400f611cba1193456ee6a5dc3e41d Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 26 Aug 2023 00:13:40 +0200 Subject: [PATCH 0223/1451] media: i2c: max9286: Fix some redundant of_node_put() calls This is odd to have a of_node_put() just after a for_each_child_of_node() or a for_each_endpoint_of_node() loop. It should already be called during the last iteration. Remove these calls. Fixes: 66d8c9d2422d ("media: i2c: Add MAX9286 driver") Signed-off-by: Christophe JAILLET Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Reviewed-by: Kieran Bingham Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/max9286.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c index be84ff1e2b170..fc1cf196ef015 100644 --- a/drivers/media/i2c/max9286.c +++ b/drivers/media/i2c/max9286.c @@ -1449,7 +1449,6 @@ static int max9286_parse_dt(struct max9286_priv *priv) i2c_mux_mask |= BIT(id); } - of_node_put(node); of_node_put(i2c_mux); /* Parse the endpoints */ @@ -1513,7 +1512,6 @@ static int max9286_parse_dt(struct max9286_priv *priv) priv->source_mask |= BIT(ep.port); priv->nsources++; } - of_node_put(node); of_property_read_u32(dev->of_node, "maxim,bus-width", &priv->bus_width); switch (priv->bus_width) { -- GitLab From 71f8a5e4be122a8737abfa6d14551480747c5e00 Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Wed, 30 Aug 2023 10:23:23 +0530 Subject: [PATCH 0224/1451] media: i2c: imx415: Use v4l2_subdev_get_fmt() The imx415 driver uses the subdev active state, there's no need to implement the .get_fmt() operation manually. Use the v4l2_subdev_get_fmt() helper instead. Signed-off-by: Umang Jain Reviewed-by: Michael Riesch Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx415.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c index 3f00172df3cc3..9a7ac81edc282 100644 --- a/drivers/media/i2c/imx415.c +++ b/drivers/media/i2c/imx415.c @@ -842,15 +842,6 @@ static int imx415_enum_frame_size(struct v4l2_subdev *sd, return 0; } -static int imx415_get_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state, - struct v4l2_subdev_format *fmt) -{ - fmt->format = *v4l2_subdev_get_pad_format(sd, state, fmt->pad); - - return 0; -} - static int imx415_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, struct v4l2_subdev_format *fmt) @@ -913,7 +904,7 @@ static const struct v4l2_subdev_video_ops imx415_subdev_video_ops = { static const struct v4l2_subdev_pad_ops imx415_subdev_pad_ops = { .enum_mbus_code = imx415_enum_mbus_code, .enum_frame_size = imx415_enum_frame_size, - .get_fmt = imx415_get_format, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = imx415_set_format, .get_selection = imx415_get_selection, .init_cfg = imx415_init_cfg, -- GitLab From da7e34e558a522d4a71660a165815979b1397074 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 18 Aug 2023 18:55:18 +0300 Subject: [PATCH 0225/1451] media: v4l2-subdev: Document that routing support depends on streams Routing support, through the subdev .set_routing() operation, requires the subdev to support streams. This is however not clearly documented anywhere. Fix it by expanding the operation's documentation to indicate that subdevs must set the V4L2_SUBDEV_FL_STREAMS flag. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- include/media/v4l2-subdev.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index d9fca929c10b5..820e38ec3dc91 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -822,8 +822,9 @@ struct v4l2_subdev_state { * operation shall fail if the pad index it has been called on * is not valid or in case of unrecoverable failures. * - * @set_routing: enable or disable data connection routes described in the - * subdevice routing table. + * @set_routing: Enable or disable data connection routes described in the + * subdevice routing table. Subdevs that implement this operation + * must set the V4L2_SUBDEV_FL_STREAMS flag. * * @enable_streams: Enable the streams defined in streams_mask on the given * source pad. Subdevs that implement this operation must use the active -- GitLab From a111f02464ca74358a001ff710334e09a22cdd7a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 23 Aug 2023 10:56:10 +0200 Subject: [PATCH 0226/1451] media: platform: use capital "OR" for multiple licenses in SPDX Documentation/process/license-rules.rst and checkpatch expect the SPDX identifier syntax for multiple licenses to use capital "OR". Correct it to keep consistent format and avoid copy-paste issues. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/platform/verisilicon/rockchip_av1_filmgrain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/verisilicon/rockchip_av1_filmgrain.c b/drivers/media/platform/verisilicon/rockchip_av1_filmgrain.c index f2ae84f0b4368..f64dea797eff2 100644 --- a/drivers/media/platform/verisilicon/rockchip_av1_filmgrain.c +++ b/drivers/media/platform/verisilicon/rockchip_av1_filmgrain.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only or Apache-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR Apache-2.0 #include "rockchip_av1_filmgrain.h" -- GitLab From d1560d57d75c05004e19cd3333e72b13940863f4 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sun, 20 Aug 2023 08:58:46 +0100 Subject: [PATCH 0227/1451] media: i2c: video-i2c: Convert enum->pointer for data in the match tables Convert enum->pointer for data in the match tables, so that device_get_match_data() can do match against OF/ACPI/I2C tables, once i2c bus type match support added to it. Replace enum->struct *video_i2c_chip for data in the match table. Simplify the probe() by replacing device_get_match_data() and ID lookup for retrieving data by i2c_get_match_data(). Signed-off-by: Biju Das Reviewed-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/video-i2c.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index 537ebd9fa8d74..178bd06cc2ed5 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -759,7 +759,6 @@ static void video_i2c_release(struct video_device *vdev) static int video_i2c_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct video_i2c_data *data; struct v4l2_device *v4l2_dev; struct vb2_queue *queue; @@ -769,11 +768,8 @@ static int video_i2c_probe(struct i2c_client *client) if (!data) return -ENOMEM; - if (dev_fwnode(&client->dev)) - data->chip = device_get_match_data(&client->dev); - else if (id) - data->chip = &video_i2c_chip[id->driver_data]; - else + data->chip = i2c_get_match_data(client); + if (!data->chip) goto error_free_device; data->regmap = regmap_init_i2c(client, data->chip->regmap_config); @@ -940,8 +936,8 @@ static const struct dev_pm_ops video_i2c_pm_ops = { }; static const struct i2c_device_id video_i2c_id_table[] = { - { "amg88xx", AMG88XX }, - { "mlx90640", MLX90640 }, + { "amg88xx", (kernel_ulong_t)&video_i2c_chip[AMG88XX] }, + { "mlx90640", (kernel_ulong_t)&video_i2c_chip[MLX90640] }, {} }; MODULE_DEVICE_TABLE(i2c, video_i2c_id_table); -- GitLab From b4e9a2d278c955715926f332773a9f66140fc41d Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Mon, 11 Sep 2023 16:56:36 +0200 Subject: [PATCH 0228/1451] media: i2c: Drop ifdeffery from sensor drivers Since commit 7d3c7d2a2914 ("media: i2c: Add a camera sensor top level menu") the CONFIG_MEDIA_CONTROLLER and CONFIG_VIDEO_V4L2_SUBDEV_API are selected by the top-level VIDEO_CAMERA_SENSOR menu. Remove all ifdefferies from camera sensor drivers to simplify the code. Compile-tested only. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/mt9m111.c | 13 +------------ drivers/media/i2c/mt9v011.c | 6 ------ drivers/media/i2c/mt9v111.c | 14 -------------- drivers/media/i2c/ov2640.c | 11 +---------- drivers/media/i2c/ov2659.c | 16 +--------------- drivers/media/i2c/ov2685.c | 12 ------------ drivers/media/i2c/ov5695.c | 19 ------------------- drivers/media/i2c/ov7670.c | 20 -------------------- drivers/media/i2c/ov772x.c | 4 ---- drivers/media/i2c/ov7740.c | 23 ++--------------------- 10 files changed, 5 insertions(+), 133 deletions(-) diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index df8d9c9e6a96c..1f44b72e8a70c 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -244,9 +244,7 @@ struct mt9m111 { bool is_streaming; /* user point of view - 0: falling 1: rising edge */ unsigned int pclk_sample:1; -#ifdef CONFIG_MEDIA_CONTROLLER struct media_pad pad; -#endif }; static const struct mt9m111_mode_info mt9m111_mode_data[MT9M111_NUM_MODES] = { @@ -527,13 +525,9 @@ static int mt9m111_get_fmt(struct v4l2_subdev *sd, return -EINVAL; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API mf = v4l2_subdev_get_try_format(sd, sd_state, format->pad); format->format = *mf; return 0; -#else - return -EINVAL; -#endif } mf->width = mt9m111->width; @@ -1120,7 +1114,6 @@ static int mt9m111_s_stream(struct v4l2_subdev *sd, int enable) static int mt9m111_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state) { -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, sd_state, 0); @@ -1132,7 +1125,7 @@ static int mt9m111_init_cfg(struct v4l2_subdev *sd, format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; format->quantization = V4L2_QUANTIZATION_DEFAULT; format->xfer_func = V4L2_XFER_FUNC_DEFAULT; -#endif + return 0; } @@ -1315,13 +1308,11 @@ static int mt9m111_probe(struct i2c_client *client) return ret; } -#ifdef CONFIG_MEDIA_CONTROLLER mt9m111->pad.flags = MEDIA_PAD_FL_SOURCE; mt9m111->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&mt9m111->subdev.entity, 1, &mt9m111->pad); if (ret < 0) goto out_hdlfree; -#endif mt9m111->current_mode = &mt9m111_mode_data[MT9M111_MODE_SXGA_15FPS]; mt9m111->frame_interval.numerator = 1; @@ -1350,10 +1341,8 @@ static int mt9m111_probe(struct i2c_client *client) return 0; out_entityclean: -#ifdef CONFIG_MEDIA_CONTROLLER media_entity_cleanup(&mt9m111->subdev.entity); out_hdlfree: -#endif v4l2_ctrl_handler_free(&mt9m111->hdl); return ret; diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c index 774861ba7747d..37a634b92cd56 100644 --- a/drivers/media/i2c/mt9v011.c +++ b/drivers/media/i2c/mt9v011.c @@ -49,9 +49,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)"); struct mt9v011 { struct v4l2_subdev sd; -#ifdef CONFIG_MEDIA_CONTROLLER struct media_pad pad; -#endif struct v4l2_ctrl_handler ctrls; unsigned width, height; unsigned xtal; @@ -483,9 +481,7 @@ static int mt9v011_probe(struct i2c_client *c) u16 version; struct mt9v011 *core; struct v4l2_subdev *sd; -#ifdef CONFIG_MEDIA_CONTROLLER int ret; -#endif /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(c->adapter, @@ -499,14 +495,12 @@ static int mt9v011_probe(struct i2c_client *c) sd = &core->sd; v4l2_i2c_subdev_init(sd, c, &mt9v011_ops); -#ifdef CONFIG_MEDIA_CONTROLLER core->pad.flags = MEDIA_PAD_FL_SOURCE; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sd->entity, 1, &core->pad); if (ret < 0) return ret; -#endif /* Check if the sensor is really a MT9V011 */ version = mt9v011_read(sd, R00_MT9V011_CHIP_VERSION); diff --git a/drivers/media/i2c/mt9v111.c b/drivers/media/i2c/mt9v111.c index 1f7edc0f5b1ab..f859b49e13bf3 100644 --- a/drivers/media/i2c/mt9v111.c +++ b/drivers/media/i2c/mt9v111.c @@ -121,9 +121,7 @@ struct mt9v111_dev { u8 addr_space; struct v4l2_subdev sd; -#if IS_ENABLED(CONFIG_MEDIA_CONTROLLER) struct media_pad pad; -#endif struct v4l2_ctrl *auto_awb; struct v4l2_ctrl *auto_exp; @@ -797,11 +795,7 @@ static struct v4l2_mbus_framefmt *__mt9v111_get_pad_format( { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: -#if IS_ENABLED(CONFIG_VIDEO_V4L2_SUBDEV_API) return v4l2_subdev_get_try_format(&mt9v111->sd, sd_state, pad); -#else - return &sd_state->pads->try_fmt; -#endif case V4L2_SUBDEV_FORMAT_ACTIVE: return &mt9v111->fmt; default: @@ -987,11 +981,9 @@ static const struct v4l2_subdev_ops mt9v111_ops = { .pad = &mt9v111_pad_ops, }; -#if IS_ENABLED(CONFIG_MEDIA_CONTROLLER) static const struct media_entity_operations mt9v111_subdev_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; -#endif /* --- V4L2 ctrl --- */ static int mt9v111_s_ctrl(struct v4l2_ctrl *ctrl) @@ -1203,7 +1195,6 @@ static int mt9v111_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&mt9v111->sd, client, &mt9v111_ops); -#if IS_ENABLED(CONFIG_MEDIA_CONTROLLER) mt9v111->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; mt9v111->sd.entity.ops = &mt9v111_subdev_entity_ops; mt9v111->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; @@ -1212,7 +1203,6 @@ static int mt9v111_probe(struct i2c_client *client) ret = media_entity_pads_init(&mt9v111->sd.entity, 1, &mt9v111->pad); if (ret) goto error_free_entity; -#endif ret = mt9v111_chip_probe(mt9v111); if (ret) @@ -1225,9 +1215,7 @@ static int mt9v111_probe(struct i2c_client *client) return 0; error_free_entity: -#if IS_ENABLED(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&mt9v111->sd.entity); -#endif error_free_ctrls: v4l2_ctrl_handler_free(&mt9v111->ctrls); @@ -1245,9 +1233,7 @@ static void mt9v111_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); -#if IS_ENABLED(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&sd->entity); -#endif v4l2_ctrl_handler_free(&mt9v111->ctrls); diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index 2d08d30175c01..28a01c6eff64f 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -293,9 +293,7 @@ struct ov2640_win_size { struct ov2640_priv { struct v4l2_subdev subdev; -#if defined(CONFIG_MEDIA_CONTROLLER) struct media_pad pad; -#endif struct v4l2_ctrl_handler hdl; u32 cfmt_code; struct clk *clk; @@ -922,13 +920,9 @@ static int ov2640_get_fmt(struct v4l2_subdev *sd, return -EINVAL; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API mf = v4l2_subdev_get_try_format(sd, sd_state, 0); format->format = *mf; return 0; -#else - return -EINVAL; -#endif } mf->width = priv->win->width; @@ -1005,7 +999,6 @@ static int ov2640_set_fmt(struct v4l2_subdev *sd, static int ov2640_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state) { -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); const struct ov2640_win_size *win = @@ -1019,7 +1012,7 @@ static int ov2640_init_cfg(struct v4l2_subdev *sd, try_fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; try_fmt->quantization = V4L2_QUANTIZATION_DEFAULT; try_fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; -#endif + return 0; } @@ -1236,13 +1229,11 @@ static int ov2640_probe(struct i2c_client *client) ret = priv->hdl.error; goto err_hdl; } -#if defined(CONFIG_MEDIA_CONTROLLER) priv->pad.flags = MEDIA_PAD_FL_SOURCE; priv->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&priv->subdev.entity, 1, &priv->pad); if (ret < 0) goto err_hdl; -#endif ret = ov2640_video_probe(client); if (ret < 0) diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c index 5429bd2eb0531..2c3dbe164eb69 100644 --- a/drivers/media/i2c/ov2659.c +++ b/drivers/media/i2c/ov2659.c @@ -1031,7 +1031,6 @@ static int ov2659_get_fmt(struct v4l2_subdev *sd, dev_dbg(&client->dev, "ov2659_get_fmt\n"); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API struct v4l2_mbus_framefmt *mf; mf = v4l2_subdev_get_try_format(sd, sd_state, 0); @@ -1039,9 +1038,6 @@ static int ov2659_get_fmt(struct v4l2_subdev *sd, fmt->format = *mf; mutex_unlock(&ov2659->lock); return 0; -#else - return -EINVAL; -#endif } mutex_lock(&ov2659->lock); @@ -1113,10 +1109,8 @@ static int ov2659_set_fmt(struct v4l2_subdev *sd, mutex_lock(&ov2659->lock); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); *mf = fmt->format; -#endif } else { s64 val; @@ -1306,7 +1300,6 @@ static int ov2659_power_on(struct device *dev) * V4L2 subdev internal operations */ -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API static int ov2659_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -1319,7 +1312,6 @@ static int ov2659_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return 0; } -#endif static const struct v4l2_subdev_core_ops ov2659_subdev_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, @@ -1338,7 +1330,6 @@ static const struct v4l2_subdev_pad_ops ov2659_subdev_pad_ops = { .set_fmt = ov2659_set_fmt, }; -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API static const struct v4l2_subdev_ops ov2659_subdev_ops = { .core = &ov2659_subdev_core_ops, .video = &ov2659_subdev_video_ops, @@ -1348,7 +1339,6 @@ static const struct v4l2_subdev_ops ov2659_subdev_ops = { static const struct v4l2_subdev_internal_ops ov2659_subdev_internal_ops = { .open = ov2659_open, }; -#endif static int ov2659_detect(struct v4l2_subdev *sd) { @@ -1489,15 +1479,12 @@ static int ov2659_probe(struct i2c_client *client) sd = &ov2659->sd; client->flags |= I2C_CLIENT_SCCB; -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API - v4l2_i2c_subdev_init(sd, client, &ov2659_subdev_ops); + v4l2_i2c_subdev_init(sd, client, &ov2659_subdev_ops); sd->internal_ops = &ov2659_subdev_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; -#endif -#if defined(CONFIG_MEDIA_CONTROLLER) ov2659->pad.flags = MEDIA_PAD_FL_SOURCE; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sd->entity, 1, &ov2659->pad); @@ -1505,7 +1492,6 @@ static int ov2659_probe(struct i2c_client *client) v4l2_ctrl_handler_free(&ov2659->ctrls); return ret; } -#endif mutex_init(&ov2659->lock); diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c index 303793e1f97d6..de0d34e43969f 100644 --- a/drivers/media/i2c/ov2685.c +++ b/drivers/media/i2c/ov2685.c @@ -547,7 +547,6 @@ static int ov2685_s_stream(struct v4l2_subdev *sd, int on) return ret; } -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API static int ov2685_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct ov2685 *ov2685 = to_ov2685(sd); @@ -563,7 +562,6 @@ static int ov2685_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return 0; } -#endif static int __maybe_unused ov2685_runtime_resume(struct device *dev) { @@ -660,11 +658,9 @@ static const struct v4l2_subdev_ops ov2685_subdev_ops = { .pad = &ov2685_pad_ops, }; -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API static const struct v4l2_subdev_internal_ops ov2685_internal_ops = { .open = ov2685_open, }; -#endif static const struct v4l2_ctrl_ops ov2685_ctrl_ops = { .s_ctrl = ov2685_set_ctrl, @@ -833,17 +829,13 @@ static int ov2685_probe(struct i2c_client *client) if (ret) goto err_power_off; -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API ov2685->subdev.internal_ops = &ov2685_internal_ops; ov2685->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; -#endif -#if defined(CONFIG_MEDIA_CONTROLLER) ov2685->pad.flags = MEDIA_PAD_FL_SOURCE; ov2685->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&ov2685->subdev.entity, 1, &ov2685->pad); if (ret < 0) goto err_power_off; -#endif ret = v4l2_async_register_subdev(&ov2685->subdev); if (ret) { @@ -858,9 +850,7 @@ static int ov2685_probe(struct i2c_client *client) return 0; err_clean_entity: -#if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&ov2685->subdev.entity); -#endif err_power_off: __ov2685_power_off(ov2685); err_free_handler: @@ -877,9 +867,7 @@ static void ov2685_remove(struct i2c_client *client) struct ov2685 *ov2685 = to_ov2685(sd); v4l2_async_unregister_subdev(sd); -#if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&sd->entity); -#endif v4l2_ctrl_handler_free(&ov2685->ctrl_handler); mutex_destroy(&ov2685->mutex); diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c index 3023b72541677..8d1c3a673c23a 100644 --- a/drivers/media/i2c/ov5695.c +++ b/drivers/media/i2c/ov5695.c @@ -821,9 +821,7 @@ static int ov5695_set_fmt(struct v4l2_subdev *sd, fmt->format.height = mode->height; fmt->format.field = V4L2_FIELD_NONE; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format; -#endif } else { ov5695->cur_mode = mode; h_blank = mode->hts_def - mode->width; @@ -849,13 +847,8 @@ static int ov5695_get_fmt(struct v4l2_subdev *sd, mutex_lock(&ov5695->mutex); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API fmt->format = *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); -#else - mutex_unlock(&ov5695->mutex); - return -EINVAL; -#endif } else { fmt->format.width = mode->width; fmt->format.height = mode->height; @@ -1048,7 +1041,6 @@ static int __maybe_unused ov5695_runtime_suspend(struct device *dev) return 0; } -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API static int ov5695_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct ov5695 *ov5695 = to_ov5695(sd); @@ -1068,18 +1060,15 @@ static int ov5695_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return 0; } -#endif static const struct dev_pm_ops ov5695_pm_ops = { SET_RUNTIME_PM_OPS(ov5695_runtime_suspend, ov5695_runtime_resume, NULL) }; -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API static const struct v4l2_subdev_internal_ops ov5695_internal_ops = { .open = ov5695_open, }; -#endif static const struct v4l2_subdev_video_ops ov5695_video_ops = { .s_stream = ov5695_s_stream, @@ -1322,17 +1311,13 @@ static int ov5695_probe(struct i2c_client *client) if (ret) goto err_power_off; -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API sd->internal_ops = &ov5695_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; -#endif -#if defined(CONFIG_MEDIA_CONTROLLER) ov5695->pad.flags = MEDIA_PAD_FL_SOURCE; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sd->entity, 1, &ov5695->pad); if (ret < 0) goto err_power_off; -#endif ret = v4l2_async_register_subdev_sensor(sd); if (ret) { @@ -1347,9 +1332,7 @@ static int ov5695_probe(struct i2c_client *client) return 0; err_clean_entity: -#if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&sd->entity); -#endif err_power_off: __ov5695_power_off(ov5695); err_free_handler: @@ -1366,9 +1349,7 @@ static void ov5695_remove(struct i2c_client *client) struct ov5695 *ov5695 = to_ov5695(sd); v4l2_async_unregister_subdev(sd); -#if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&sd->entity); -#endif v4l2_ctrl_handler_free(&ov5695->ctrl_handler); mutex_destroy(&ov5695->mutex); diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 2f55491ef571f..85bf745c0badd 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -217,9 +217,7 @@ struct ov7670_devtype { struct ov7670_format_struct; /* coming later */ struct ov7670_info { struct v4l2_subdev sd; -#if defined(CONFIG_MEDIA_CONTROLLER) struct media_pad pad; -#endif struct v4l2_ctrl_handler hdl; struct { /* gain cluster */ @@ -1108,9 +1106,7 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_format *format) { struct ov7670_info *info = to_state(sd); -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API struct v4l2_mbus_framefmt *mbus_fmt; -#endif int ret; if (format->pad) @@ -1120,11 +1116,9 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, ret = ov7670_try_fmt_internal(sd, &format->format, NULL, NULL); if (ret) return ret; -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad); *mbus_fmt = format->format; -#endif return 0; } @@ -1148,18 +1142,12 @@ static int ov7670_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_format *format) { struct ov7670_info *info = to_state(sd); -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API struct v4l2_mbus_framefmt *mbus_fmt; -#endif if (format->which == V4L2_SUBDEV_FORMAT_TRY) { -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); format->format = *mbus_fmt; return 0; -#else - return -EINVAL; -#endif } else { format->format = info->format; } @@ -1720,7 +1708,6 @@ static void ov7670_get_default_format(struct v4l2_subdev *sd, format->field = V4L2_FIELD_NONE; } -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API static int ov7670_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_mbus_framefmt *format = @@ -1730,7 +1717,6 @@ static int ov7670_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return 0; } -#endif /* ----------------------------------------------------------------------- */ @@ -1766,11 +1752,9 @@ static const struct v4l2_subdev_ops ov7670_ops = { .pad = &ov7670_pad_ops, }; -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API static const struct v4l2_subdev_internal_ops ov7670_subdev_internal_ops = { .open = ov7670_open, }; -#endif /* ----------------------------------------------------------------------- */ @@ -1861,10 +1845,8 @@ static int ov7670_probe(struct i2c_client *client) sd = &info->sd; v4l2_i2c_subdev_init(sd, client, &ov7670_ops); -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API sd->internal_ops = &ov7670_subdev_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; -#endif info->clock_speed = 30; /* default: a guess */ @@ -1977,13 +1959,11 @@ static int ov7670_probe(struct i2c_client *client) V4L2_EXPOSURE_MANUAL, false); v4l2_ctrl_cluster(2, &info->saturation); -#if defined(CONFIG_MEDIA_CONTROLLER) info->pad.flags = MEDIA_PAD_FL_SOURCE; info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); if (ret < 0) goto hdl_free; -#endif v4l2_ctrl_handler_setup(&info->hdl); diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 386d69c8e0746..7618b58a7ad05 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -433,9 +433,7 @@ struct ov772x_priv { struct mutex lock; int power_count; int streaming; -#ifdef CONFIG_MEDIA_CONTROLLER struct media_pad pad; -#endif enum v4l2_mbus_type bus_type; }; @@ -1488,13 +1486,11 @@ static int ov772x_probe(struct i2c_client *client) if (ret < 0) goto error_gpio_put; -#ifdef CONFIG_MEDIA_CONTROLLER priv->pad.flags = MEDIA_PAD_FL_SOURCE; priv->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&priv->subdev.entity, 1, &priv->pad); if (ret < 0) goto error_gpio_put; -#endif priv->cfmt = &ov772x_cfmts[0]; priv->win = &ov772x_win_sizes[0]; diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index dffdb475e4339..78d04ce68971a 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -83,9 +83,7 @@ struct ov7740 { struct v4l2_subdev subdev; -#if defined(CONFIG_MEDIA_CONTROLLER) struct media_pad pad; -#endif struct v4l2_mbus_framefmt format; const struct ov7740_pixfmt *fmt; /* Current format */ const struct ov7740_framesize *frmsize; @@ -807,9 +805,7 @@ static int ov7740_set_fmt(struct v4l2_subdev *sd, struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); const struct ov7740_pixfmt *ovfmt; const struct ov7740_framesize *fsize; -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API struct v4l2_mbus_framefmt *mbus_fmt; -#endif int ret; mutex_lock(&ov7740->mutex); @@ -822,11 +818,10 @@ static int ov7740_set_fmt(struct v4l2_subdev *sd, ret = ov7740_try_fmt_internal(sd, &format->format, NULL, NULL); if (ret) goto error; -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad); *mbus_fmt = format->format; -#endif mutex_unlock(&ov7740->mutex); return 0; } @@ -851,26 +846,18 @@ static int ov7740_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_format *format) { struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API struct v4l2_mbus_framefmt *mbus_fmt; -#endif - int ret = 0; mutex_lock(&ov7740->mutex); if (format->which == V4L2_SUBDEV_FORMAT_TRY) { -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); format->format = *mbus_fmt; - ret = 0; -#else - ret = -EINVAL; -#endif } else { format->format = ov7740->format; } mutex_unlock(&ov7740->mutex); - return ret; + return 0; } static const struct v4l2_subdev_pad_ops ov7740_subdev_pad_ops = { @@ -899,7 +886,6 @@ static void ov7740_get_default_format(struct v4l2_subdev *sd, format->field = V4L2_FIELD_NONE; } -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API static int ov7740_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); @@ -916,7 +902,6 @@ static int ov7740_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) static const struct v4l2_subdev_internal_ops ov7740_subdev_internal_ops = { .open = ov7740_open, }; -#endif static int ov7740_probe_dt(struct i2c_client *client, struct ov7740 *ov7740) @@ -1094,18 +1079,14 @@ static int ov7740_probe(struct i2c_client *client) sd = &ov7740->subdev; v4l2_i2c_subdev_init(sd, client, &ov7740_subdev_ops); -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API sd->internal_ops = &ov7740_subdev_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; -#endif -#if defined(CONFIG_MEDIA_CONTROLLER) ov7740->pad.flags = MEDIA_PAD_FL_SOURCE; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sd->entity, 1, &ov7740->pad); if (ret) return ret; -#endif ret = ov7740_set_power(ov7740, 1); if (ret) -- GitLab From 5e1abb1a9bf29a35ac74f480307d4d18a3b8eb1c Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sun, 10 Sep 2023 17:54:31 +0100 Subject: [PATCH 0229/1451] media: i2c: mt9v032: Extend match support for OF tables The driver has an OF match table, still, it uses an ID lookup table for retrieving match data. Currently, the driver is working on the assumption that an I2C device registered via OF will always match a legacy I2C device ID. The correct approach is to have an OF device ID table using i2c_get_match_data() if the devices are registered via OF/ID. Unify the OF/ID table by using mt9v032_model_info as match data for both these tables and replace the ID lookup table for the match data by i2c_get_match_data() and simplifly probe(). Signed-off-by: Biju Das Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/mt9v032.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index 00e7bc6e3235c..0f448aa27e532 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -1046,7 +1046,6 @@ mt9v032_get_pdata(struct i2c_client *client) static int mt9v032_probe(struct i2c_client *client) { - const struct i2c_device_id *did = i2c_client_get_device_id(client); struct mt9v032_platform_data *pdata = mt9v032_get_pdata(client); struct mt9v032 *mt9v032; unsigned int i; @@ -1076,7 +1075,7 @@ static int mt9v032_probe(struct i2c_client *client) mutex_init(&mt9v032->power_lock); mt9v032->pdata = pdata; - mt9v032->model = (const void *)did->driver_data; + mt9v032->model = i2c_get_match_data(client); v4l2_ctrl_handler_init(&mt9v032->ctrls, 11 + ARRAY_SIZE(mt9v032_aegc_controls)); @@ -1272,20 +1271,20 @@ static const struct i2c_device_id mt9v032_id[] = { { "mt9v032m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V032_MONO] }, { "mt9v034", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V034_COLOR] }, { "mt9v034m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V034_MONO] }, - { } + { /* Sentinel */ } }; MODULE_DEVICE_TABLE(i2c, mt9v032_id); #if IS_ENABLED(CONFIG_OF) static const struct of_device_id mt9v032_of_match[] = { - { .compatible = "aptina,mt9v022" }, - { .compatible = "aptina,mt9v022m" }, - { .compatible = "aptina,mt9v024" }, - { .compatible = "aptina,mt9v024m" }, - { .compatible = "aptina,mt9v032" }, - { .compatible = "aptina,mt9v032m" }, - { .compatible = "aptina,mt9v034" }, - { .compatible = "aptina,mt9v034m" }, + { .compatible = "aptina,mt9v022", .data = &mt9v032_models[MT9V032_MODEL_V022_COLOR] }, + { .compatible = "aptina,mt9v022m", .data = &mt9v032_models[MT9V032_MODEL_V022_MONO] }, + { .compatible = "aptina,mt9v024", .data = &mt9v032_models[MT9V032_MODEL_V024_COLOR] }, + { .compatible = "aptina,mt9v024m", .data = &mt9v032_models[MT9V032_MODEL_V024_MONO] }, + { .compatible = "aptina,mt9v032", .data = &mt9v032_models[MT9V032_MODEL_V032_COLOR] }, + { .compatible = "aptina,mt9v032m", .data = &mt9v032_models[MT9V032_MODEL_V032_MONO] }, + { .compatible = "aptina,mt9v034", .data = &mt9v032_models[MT9V032_MODEL_V034_COLOR] }, + { .compatible = "aptina,mt9v034m", .data = &mt9v032_models[MT9V032_MODEL_V034_MONO] }, { /* Sentinel */ } }; MODULE_DEVICE_TABLE(of, mt9v032_of_match); -- GitLab From 578295176d5caaf0a91314826152b4b3a5766320 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sun, 10 Sep 2023 17:54:32 +0100 Subject: [PATCH 0230/1451] media: i2c: mt9v032: Drop CONFIG_OF ifdeffery Drop of_match_ptr() from mt9v032_driver and get rid of ugly CONFIG_OF if check. This slightly increases the size of mt9v032_driver on non-OF system and shouldn't be an issue. Add mod_devicetable.h include. It also allows, in case if needed, to enumerate this device via ACPI with PRP0001 magic. Signed-off-by: Biju Das Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/mt9v032.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index 0f448aa27e532..1c6f6cea12045 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -1275,7 +1276,6 @@ static const struct i2c_device_id mt9v032_id[] = { }; MODULE_DEVICE_TABLE(i2c, mt9v032_id); -#if IS_ENABLED(CONFIG_OF) static const struct of_device_id mt9v032_of_match[] = { { .compatible = "aptina,mt9v022", .data = &mt9v032_models[MT9V032_MODEL_V022_COLOR] }, { .compatible = "aptina,mt9v022m", .data = &mt9v032_models[MT9V032_MODEL_V022_MONO] }, @@ -1288,12 +1288,11 @@ static const struct of_device_id mt9v032_of_match[] = { { /* Sentinel */ } }; MODULE_DEVICE_TABLE(of, mt9v032_of_match); -#endif static struct i2c_driver mt9v032_driver = { .driver = { .name = "mt9v032", - .of_match_table = of_match_ptr(mt9v032_of_match), + .of_match_table = mt9v032_of_match, }, .probe = mt9v032_probe, .remove = mt9v032_remove, -- GitLab From dd2dbf3cbd3f091f20860586f1115eb0fa513d5d Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sun, 10 Sep 2023 16:00:32 +0100 Subject: [PATCH 0231/1451] media: i2c: ov7670: Extend match support for OF tables The driver has an OF match table, still, it uses an ID lookup table for retrieving match data. Currently, the driver is working on the assumption that an I2C device registered via OF will always match a legacy I2C device ID. The correct approach is to have an OF device ID table using i2c_get_match_data() if the devices are registered via OF/ID. Unify the OF/ID table by using struct ov7670_devtype as match data for both these tables and replace the ID lookup table for the match data by i2c_get_match_data(). Split the array ov7670_devdata[] as individual variables, and make lines shorter by referring to e.g. &ov7670_devdata instead of &ov7670_devdata[MODEL_OV7670]. Drop enum ov7670_model as there is no user. While at it, remove the trailing comma in the terminator entry for the OF table making code robust against (theoretical) misrebases or other similar things where the new entry goes _after_ the termination without the compiler noticing. Signed-off-by: Biju Das Reviewed-by: Kieran Bingham Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov7670.c | 47 ++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 85bf745c0badd..b70d65f5c18a6 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -186,11 +186,6 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); #define REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */ #define REG_BD60MAX 0xab /* 60hz banding step limit */ -enum ov7670_model { - MODEL_OV7670 = 0, - MODEL_OV7675, -}; - struct ov7670_win_size { int width; int height; @@ -1758,21 +1753,6 @@ static const struct v4l2_subdev_internal_ops ov7670_subdev_internal_ops = { /* ----------------------------------------------------------------------- */ -static const struct ov7670_devtype ov7670_devdata[] = { - [MODEL_OV7670] = { - .win_sizes = ov7670_win_sizes, - .n_win_sizes = ARRAY_SIZE(ov7670_win_sizes), - .set_framerate = ov7670_set_framerate_legacy, - .get_framerate = ov7670_get_framerate_legacy, - }, - [MODEL_OV7675] = { - .win_sizes = ov7675_win_sizes, - .n_win_sizes = ARRAY_SIZE(ov7675_win_sizes), - .set_framerate = ov7675_set_framerate, - .get_framerate = ov7675_get_framerate, - }, -}; - static int ov7670_init_gpio(struct i2c_client *client, struct ov7670_info *info) { info->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown", @@ -1833,7 +1813,6 @@ static int ov7670_parse_dt(struct device *dev, static int ov7670_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct v4l2_fract tpf; struct v4l2_subdev *sd; struct ov7670_info *info; @@ -1905,7 +1884,7 @@ static int ov7670_probe(struct i2c_client *client) v4l_info(client, "chip found @ 0x%02x (%s)\n", client->addr << 1, client->adapter->name); - info->devtype = &ov7670_devdata[id->driver_data]; + info->devtype = i2c_get_match_data(client); info->fmt = &ov7670_formats[0]; info->wsize = &info->devtype->win_sizes[0]; @@ -1993,17 +1972,31 @@ static void ov7670_remove(struct i2c_client *client) media_entity_cleanup(&info->sd.entity); } +static const struct ov7670_devtype ov7670_devdata = { + .win_sizes = ov7670_win_sizes, + .n_win_sizes = ARRAY_SIZE(ov7670_win_sizes), + .set_framerate = ov7670_set_framerate_legacy, + .get_framerate = ov7670_get_framerate_legacy, +}; + +static const struct ov7670_devtype ov7675_devdata = { + .win_sizes = ov7675_win_sizes, + .n_win_sizes = ARRAY_SIZE(ov7675_win_sizes), + .set_framerate = ov7675_set_framerate, + .get_framerate = ov7675_get_framerate, +}; + static const struct i2c_device_id ov7670_id[] = { - { "ov7670", MODEL_OV7670 }, - { "ov7675", MODEL_OV7675 }, - { } + { "ov7670", (kernel_ulong_t)&ov7670_devdata }, + { "ov7675", (kernel_ulong_t)&ov7675_devdata }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, ov7670_id); #if IS_ENABLED(CONFIG_OF) static const struct of_device_id ov7670_of_match[] = { - { .compatible = "ovti,ov7670", }, - { /* sentinel */ }, + { .compatible = "ovti,ov7670", &ov7670_devdata }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, ov7670_of_match); #endif -- GitLab From 2d13621c6b7b5290c8114c8c33e8e66297ce26bf Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sun, 10 Sep 2023 16:00:33 +0100 Subject: [PATCH 0232/1451] media: i2c: ov7670: Drop CONFIG_OF ifdeffery Drop of_match_ptr() from ov7670_driver and get rid of ugly CONFIG_OF if check. This slightly increases the size of ov7670_driver on non-OF system and shouldn't be an issue. Add mod_devicetable.h include. It also allows, in case if needed, to enumerate this device via ACPI with PRP0001 magic. Signed-off-by: Biju Das Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov7670.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index b70d65f5c18a6..172483597c542 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -10,6 +10,7 @@ */ #include #include +#include #include #include #include @@ -1993,18 +1994,16 @@ static const struct i2c_device_id ov7670_id[] = { }; MODULE_DEVICE_TABLE(i2c, ov7670_id); -#if IS_ENABLED(CONFIG_OF) static const struct of_device_id ov7670_of_match[] = { { .compatible = "ovti,ov7670", &ov7670_devdata }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, ov7670_of_match); -#endif static struct i2c_driver ov7670_driver = { .driver = { .name = "ov7670", - .of_match_table = of_match_ptr(ov7670_of_match), + .of_match_table = ov7670_of_match, }, .probe = ov7670_probe, .remove = ov7670_remove, -- GitLab From a6403dddaebf32a3cad3763924a10be02ed327e0 Mon Sep 17 00:00:00 2001 From: Shravan Chippa Date: Fri, 4 Aug 2023 20:45:41 +0530 Subject: [PATCH 0233/1451] media: i2c: imx334: add support for test pattern generator Add support for the imx334's test pattern generator. By default the test pattern generator is disabled, so add support for enabling and disabling horizontal and vertical colour bars. Signed-off-by: Shravan Chippa Acked-by: Daniele Alessandrelli Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx334.c | 57 +++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx334.c b/drivers/media/i2c/imx334.c index d722c9b7cd31d..91c79af70734f 100644 --- a/drivers/media/i2c/imx334.c +++ b/drivers/media/i2c/imx334.c @@ -56,6 +56,24 @@ #define IMX334_REG_MIN 0x00 #define IMX334_REG_MAX 0xfffff +/* Test Pattern Control */ +#define IMX334_REG_TP 0x329e +#define IMX334_TP_COLOR_HBARS 0xA +#define IMX334_TP_COLOR_VBARS 0xB + +#define IMX334_TPG_EN_DOUT 0x329c +#define IMX334_TP_ENABLE 0x1 +#define IMX334_TP_DISABLE 0x0 + +#define IMX334_TPG_COLORW 0x32a0 +#define IMX334_TPG_COLORW_120P 0x13 + +#define IMX334_TP_CLK_EN 0x3148 +#define IMX334_TP_CLK_EN_VAL 0x10 +#define IMX334_TP_CLK_DIS_VAL 0x0 + +#define IMX334_DIG_CLP_MODE 0x3280 + /** * struct imx334_reg - imx334 sensor register * @address: Register address @@ -430,6 +448,18 @@ static const struct imx334_reg mode_3840x2160_regs[] = { {0x3a29, 0x00}, }; +static const char * const imx334_test_pattern_menu[] = { + "Disabled", + "Vertical Color Bars", + "Horizontal Color Bars", +}; + +static const int imx334_test_pattern_val[] = { + IMX334_TP_DISABLE, + IMX334_TP_COLOR_HBARS, + IMX334_TP_COLOR_VBARS, +}; + static const struct imx334_reg raw10_framefmt_regs[] = { {0x3050, 0x00}, {0x319d, 0x00}, @@ -716,6 +746,26 @@ static int imx334_set_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_HBLANK: ret = 0; break; + case V4L2_CID_TEST_PATTERN: + if (ctrl->val) { + imx334_write_reg(imx334, IMX334_TP_CLK_EN, 1, + IMX334_TP_CLK_EN_VAL); + imx334_write_reg(imx334, IMX334_DIG_CLP_MODE, 1, 0x0); + imx334_write_reg(imx334, IMX334_TPG_COLORW, 1, + IMX334_TPG_COLORW_120P); + imx334_write_reg(imx334, IMX334_REG_TP, 1, + imx334_test_pattern_val[ctrl->val]); + imx334_write_reg(imx334, IMX334_TPG_EN_DOUT, 1, + IMX334_TP_ENABLE); + } else { + imx334_write_reg(imx334, IMX334_DIG_CLP_MODE, 1, 0x1); + imx334_write_reg(imx334, IMX334_TP_CLK_EN, 1, + IMX334_TP_CLK_DIS_VAL); + imx334_write_reg(imx334, IMX334_TPG_EN_DOUT, 1, + IMX334_TP_DISABLE); + } + ret = 0; + break; default: dev_err(imx334->dev, "Invalid control %d", ctrl->id); ret = -EINVAL; @@ -1222,7 +1272,7 @@ static int imx334_init_controls(struct imx334 *imx334) u32 lpfr; int ret; - ret = v4l2_ctrl_handler_init(ctrl_hdlr, 6); + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 7); if (ret) return ret; @@ -1282,6 +1332,11 @@ static int imx334_init_controls(struct imx334 *imx334) if (imx334->hblank_ctrl) imx334->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx334_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(imx334_test_pattern_menu) - 1, + 0, 0, imx334_test_pattern_menu); + if (ctrl_hdlr->error) { dev_err(imx334->dev, "control init failed: %d", ctrl_hdlr->error); -- GitLab From 20290feaaeb76cc719921aad275ccb18662a7c3a Mon Sep 17 00:00:00 2001 From: Xiaolei Wang Date: Mon, 7 Aug 2023 17:05:35 +0800 Subject: [PATCH 0234/1451] media: ov5640: Fix a memory leak when ov5640_probe fails sensor->ctrls.handler is initialized in ov5640_init_controls(), so when the sensor is not connected and ov5640_sensor_resume() fails, sensor->ctrls.handler should be released, otherwise a memory leak will be detected: unreferenced object 0xc674ca80 (size 64): comm "swapper/0", pid 1, jiffies 4294938337 (age 204.880s) hex dump (first 32 bytes): 80 55 75 c6 80 54 75 c6 00 55 75 c6 80 52 75 c6 .Uu..Tu..Uu..Ru. 00 53 75 c6 00 00 00 00 00 00 00 00 00 00 00 00 .Su.......... Fixes: 85644a9b37ec ("media: ov5640: Use runtime PM") Signed-off-by: Xiaolei Wang Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov5640.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 1c9cda1e7df5c..40532f7bcabea 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -3928,7 +3928,7 @@ static int ov5640_probe(struct i2c_client *client) ret = ov5640_sensor_resume(dev); if (ret) { dev_err(dev, "failed to power on\n"); - goto entity_cleanup; + goto free_ctrls; } pm_runtime_set_active(dev); @@ -3953,8 +3953,9 @@ static int ov5640_probe(struct i2c_client *client) err_pm_runtime: pm_runtime_put_noidle(dev); pm_runtime_disable(dev); - v4l2_ctrl_handler_free(&sensor->ctrls.handler); ov5640_sensor_suspend(dev); +free_ctrls: + v4l2_ctrl_handler_free(&sensor->ctrls.handler); entity_cleanup: media_entity_cleanup(&sensor->sd.entity); mutex_destroy(&sensor->lock); -- GitLab From b92f8f3591aca18fe677092fcc567c698368f651 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 20:20:54 +0300 Subject: [PATCH 0235/1451] media: i2c: Use pm_runtime_resume_and_get() Simplify error handling by using pm_runtime_resume_and_get() instead of pm_runtime_get_sync() with a put call in the error path. Signed-off-by: Laurent Pinchart Acked-by: Benjamin Mugnier (st-vgxy61) Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ccs/ccs-core.c | 6 +++--- drivers/media/i2c/hi846.c | 6 ++---- drivers/media/i2c/hi847.c | 5 ++--- drivers/media/i2c/imx208.c | 14 +++++++------- drivers/media/i2c/og01a1b.c | 5 ++--- drivers/media/i2c/ov5693.c | 6 +++--- drivers/media/i2c/ov7251.c | 8 +++++--- drivers/media/i2c/st-vgxy61.c | 9 ++------- 8 files changed, 26 insertions(+), 33 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 49e0d9a095302..569bf9b67539a 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -1893,9 +1893,9 @@ static int ccs_pm_get_init(struct ccs_sensor *sensor) * relies at the returned value to detect if the device was already * active or not. */ - rval = pm_runtime_get_sync(&client->dev); - if (rval < 0) - goto error; + rval = pm_runtime_resume_and_get(&client->dev); + if (rval) + return rval; /* Device was already active, so don't set controls */ if (rval == 1) diff --git a/drivers/media/i2c/hi846.c b/drivers/media/i2c/hi846.c index fa0038749a3b9..8a8ae89a84539 100644 --- a/drivers/media/i2c/hi846.c +++ b/drivers/media/i2c/hi846.c @@ -1613,11 +1613,9 @@ static int hi846_set_stream(struct v4l2_subdev *sd, int enable) mutex_lock(&hi846->mutex); if (enable) { - ret = pm_runtime_get_sync(&client->dev); - if (ret < 0) { - pm_runtime_put_noidle(&client->dev); + ret = pm_runtime_resume_and_get(&client->dev); + if (ret) goto out; - } ret = hi846_start_streaming(hi846); } diff --git a/drivers/media/i2c/hi847.c b/drivers/media/i2c/hi847.c index 32547d7a2659f..47aa2cd06e32d 100644 --- a/drivers/media/i2c/hi847.c +++ b/drivers/media/i2c/hi847.c @@ -2623,9 +2623,8 @@ static int hi847_set_stream(struct v4l2_subdev *sd, int enable) mutex_lock(&hi847->mutex); if (enable) { - ret = pm_runtime_get_sync(&client->dev); - if (ret < 0) { - pm_runtime_put_noidle(&client->dev); + ret = pm_runtime_resume_and_get(&client->dev); + if (ret) { mutex_unlock(&hi847->mutex); return ret; } diff --git a/drivers/media/i2c/imx208.c b/drivers/media/i2c/imx208.c index ee5a286753884..a6edcae4ef47e 100644 --- a/drivers/media/i2c/imx208.c +++ b/drivers/media/i2c/imx208.c @@ -720,9 +720,11 @@ static int imx208_set_stream(struct v4l2_subdev *sd, int enable) } if (enable) { - ret = pm_runtime_get_sync(&client->dev); - if (ret < 0) - goto err_rpm_put; + ret = pm_runtime_resume_and_get(&client->dev); + if (ret) { + mutex_unlock(&imx208->imx208_mx); + return ret; + } /* * Apply default & customized values @@ -819,11 +821,9 @@ static int imx208_read_otp(struct imx208 *imx208) if (imx208->otp_read) goto out_unlock; - ret = pm_runtime_get_sync(&client->dev); - if (ret < 0) { - pm_runtime_put_noidle(&client->dev); + ret = pm_runtime_resume_and_get(&client->dev); + if (ret) goto out_unlock; - } ret = imx208_identify_module(imx208); if (ret) diff --git a/drivers/media/i2c/og01a1b.c b/drivers/media/i2c/og01a1b.c index 365ce56845836..ccf6731ea2e22 100644 --- a/drivers/media/i2c/og01a1b.c +++ b/drivers/media/i2c/og01a1b.c @@ -737,9 +737,8 @@ static int og01a1b_set_stream(struct v4l2_subdev *sd, int enable) mutex_lock(&og01a1b->mutex); if (enable) { - ret = pm_runtime_get_sync(&client->dev); - if (ret < 0) { - pm_runtime_put_noidle(&client->dev); + ret = pm_runtime_resume_and_get(&client->dev); + if (ret) { mutex_unlock(&og01a1b->mutex); return ret; } diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c index 488ee6d9d3010..033cf7f14f192 100644 --- a/drivers/media/i2c/ov5693.c +++ b/drivers/media/i2c/ov5693.c @@ -975,9 +975,9 @@ static int ov5693_s_stream(struct v4l2_subdev *sd, int enable) int ret; if (enable) { - ret = pm_runtime_get_sync(ov5693->dev); - if (ret < 0) - goto err_power_down; + ret = pm_runtime_resume_and_get(ov5693->dev); + if (ret) + return ret; mutex_lock(&ov5693->lock); ret = __v4l2_ctrl_handler_setup(&ov5693->ctrls.handler); diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c index 675fb37a6feae..6582cc0e2384e 100644 --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c @@ -1340,9 +1340,11 @@ static int ov7251_s_stream(struct v4l2_subdev *subdev, int enable) mutex_lock(&ov7251->lock); if (enable) { - ret = pm_runtime_get_sync(ov7251->dev); - if (ret < 0) - goto err_power_down; + ret = pm_runtime_resume_and_get(ov7251->dev); + if (ret) { + mutex_unlock(&ov7251->lock); + return ret; + } ret = ov7251_pll_configure(ov7251); if (ret) { diff --git a/drivers/media/i2c/st-vgxy61.c b/drivers/media/i2c/st-vgxy61.c index 30f82ca344c44..5dbfb04b31248 100644 --- a/drivers/media/i2c/st-vgxy61.c +++ b/drivers/media/i2c/st-vgxy61.c @@ -1170,14 +1170,9 @@ static int vgxy61_stream_enable(struct vgxy61_dev *sensor) if (ret) return ret; - ret = pm_runtime_get_sync(&client->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(&client->dev); + ret = pm_runtime_resume_and_get(&client->dev); + if (ret) return ret; - } - - /* pm_runtime_get_sync() can return 1 as a valid return code */ - ret = 0; vgxy61_write_reg(sensor, VGXY61_REG_FORMAT_CTRL, get_bpp_by_code(sensor->fmt.code), &ret); -- GitLab From 165457e6d084c308dd9399a04c71ee85bb28d300 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 20:45:08 +0300 Subject: [PATCH 0236/1451] media: i2c: ov5693: Drop the unused streaming flag The streaming flag in the driver's private structure is set but never used. Drop it. Signed-off-by: Laurent Pinchart Reviewed-by: Daniel Scally Reviewed-by: Tommaso Merciai Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov5693.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c index 033cf7f14f192..819425e213499 100644 --- a/drivers/media/i2c/ov5693.c +++ b/drivers/media/i2c/ov5693.c @@ -154,7 +154,6 @@ struct ov5693_device { unsigned int inc_y_odd; unsigned int vts; } mode; - bool streaming; struct v4l2_subdev sd; struct media_pad pad; @@ -996,8 +995,6 @@ static int ov5693_s_stream(struct v4l2_subdev *sd, int enable) if (ret) goto err_power_down; - ov5693->streaming = !!enable; - if (!enable) pm_runtime_put(ov5693->dev); -- GitLab From b2b5905aa5a3efb4dcbc4ac3f5f0525190a3e3a8 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 20:46:00 +0300 Subject: [PATCH 0237/1451] media: i2c: imx415: Replace streaming flag with runtime PM check The streaming flag in the driver private structure is used for the sole purpose of gating register writes when setting a V4L2 control. This is better handled by checking if the sensor is powered up using the runtime PM API. Do so and drop the streaming flag. Signed-off-by: Laurent Pinchart [Sakari Ailus: Runtime PM put when setting analgue gain.] Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx415.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c index 9a7ac81edc282..b3fa71a168397 100644 --- a/drivers/media/i2c/imx415.c +++ b/drivers/media/i2c/imx415.c @@ -353,8 +353,6 @@ struct imx415 { const struct imx415_clk_params *clk_params; - bool streaming; - struct v4l2_subdev subdev; struct media_pad pad; @@ -542,8 +540,9 @@ static int imx415_s_ctrl(struct v4l2_ctrl *ctrl) struct v4l2_subdev_state *state; unsigned int vmax; unsigned int flip; + int ret; - if (!sensor->streaming) + if (!pm_runtime_get_if_in_use(sensor->dev)) return 0; state = v4l2_subdev_get_locked_active_state(&sensor->subdev); @@ -554,24 +553,33 @@ static int imx415_s_ctrl(struct v4l2_ctrl *ctrl) /* clamp the exposure value to VMAX. */ vmax = format->height + sensor->vblank->cur.val; ctrl->val = min_t(int, ctrl->val, vmax); - return imx415_write(sensor, IMX415_SHR0, vmax - ctrl->val); + ret = imx415_write(sensor, IMX415_SHR0, vmax - ctrl->val); + break; case V4L2_CID_ANALOGUE_GAIN: /* analogue gain in 0.3 dB step size */ - return imx415_write(sensor, IMX415_GAIN_PCG_0, ctrl->val); + ret = imx415_write(sensor, IMX415_GAIN_PCG_0, ctrl->val); + break; case V4L2_CID_HFLIP: case V4L2_CID_VFLIP: flip = (sensor->hflip->val << IMX415_HREVERSE_SHIFT) | (sensor->vflip->val << IMX415_VREVERSE_SHIFT); - return imx415_write(sensor, IMX415_REVERSE, flip); + ret = imx415_write(sensor, IMX415_REVERSE, flip); + break; case V4L2_CID_TEST_PATTERN: - return imx415_set_testpattern(sensor, ctrl->val); + ret = imx415_set_testpattern(sensor, ctrl->val); + break; default: - return -EINVAL; + ret = -EINVAL; + break; } + + pm_runtime_put(sensor->dev); + + return ret; } static const struct v4l2_ctrl_ops imx415_ctrl_ops = { @@ -766,8 +774,6 @@ static int imx415_s_stream(struct v4l2_subdev *sd, int enable) pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); - sensor->streaming = false; - goto unlock; } @@ -779,13 +785,6 @@ static int imx415_s_stream(struct v4l2_subdev *sd, int enable) if (ret) goto err_pm; - /* - * Set streaming to true to ensure __v4l2_ctrl_handler_setup() will set - * the controls. The flag is reset to false further down if an error - * occurs. - */ - sensor->streaming = true; - ret = __v4l2_ctrl_handler_setup(&sensor->ctrls); if (ret < 0) goto err_pm; @@ -807,7 +806,6 @@ static int imx415_s_stream(struct v4l2_subdev *sd, int enable) * likely has no other chance to recover. */ pm_runtime_put_sync(sensor->dev); - sensor->streaming = false; goto unlock; } -- GitLab From def13c37e772b762f86dbfbd322d8ee333ecbc5d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 20:46:47 +0300 Subject: [PATCH 0238/1451] media: i2c: imx296: Replace streaming flag with runtime PM check The streaming flag in the driver private structure is used for the sole purpose of gating register writes when setting a V4L2 control. This is better handled by checking if the sensor is powered up using the runtime PM API. Do so and drop the streaming flag. Signed-off-by: Laurent Pinchart Reviewed-by: Tommaso Merciai Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx296.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/media/i2c/imx296.c b/drivers/media/i2c/imx296.c index 3b4539b622b43..94aac9d2732f1 100644 --- a/drivers/media/i2c/imx296.c +++ b/drivers/media/i2c/imx296.c @@ -201,8 +201,6 @@ struct imx296 { const struct imx296_clk_params *clk_params; bool mono; - bool streaming; - struct v4l2_subdev subdev; struct media_pad pad; @@ -321,7 +319,7 @@ static int imx296_s_ctrl(struct v4l2_ctrl *ctrl) unsigned int vmax; int ret = 0; - if (!sensor->streaming) + if (!pm_runtime_get_if_in_use(sensor->dev)) return 0; state = v4l2_subdev_get_locked_active_state(&sensor->subdev); @@ -376,6 +374,8 @@ static int imx296_s_ctrl(struct v4l2_ctrl *ctrl) break; } + pm_runtime_put(sensor->dev); + return ret; } @@ -607,8 +607,6 @@ static int imx296_s_stream(struct v4l2_subdev *sd, int enable) pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); - sensor->streaming = false; - goto unlock; } @@ -620,13 +618,6 @@ static int imx296_s_stream(struct v4l2_subdev *sd, int enable) if (ret < 0) goto err_pm; - /* - * Set streaming to true to ensure __v4l2_ctrl_handler_setup() will set - * the controls. The flag is reset to false further down if an error - * occurs. - */ - sensor->streaming = true; - ret = __v4l2_ctrl_handler_setup(&sensor->ctrls); if (ret < 0) goto err_pm; @@ -646,7 +637,6 @@ static int imx296_s_stream(struct v4l2_subdev *sd, int enable) * likely has no other chance to recover. */ pm_runtime_put_sync(sensor->dev); - sensor->streaming = false; goto unlock; } -- GitLab From 4af8528f90e6a2c030598162c62d012c122a1e20 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 15 Sep 2023 01:01:24 +0300 Subject: [PATCH 0239/1451] media: Documentation: Mention CCS tools CCS tools is a useful set of programs and libraries for working with CCS static data. Do mention that in context of the CCS driver. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- Documentation/driver-api/media/drivers/ccs/ccs.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/driver-api/media/drivers/ccs/ccs.rst b/Documentation/driver-api/media/drivers/ccs/ccs.rst index 7389204afcb82..0468b9413a318 100644 --- a/Documentation/driver-api/media/drivers/ccs/ccs.rst +++ b/Documentation/driver-api/media/drivers/ccs/ccs.rst @@ -78,6 +78,14 @@ For SMIA (non-++) compliant devices the static data file name is vvvv or vv denotes MIPI and SMIA manufacturer IDs respectively, mmmm model ID and rrrr or rr revision number. +CCS tools +~~~~~~~~~ + +`CCS tools `_ is a set of +tools for working with CCS static data files. CCS tools includes a +definition of the human-readable CCS static data YAML format and includes a +program to convert it to a binary. + Register definition generator ----------------------------- -- GitLab From 3a5c419fff2428d2ff7d6501476b02da6195cfa3 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 13 Sep 2023 16:28:11 -0300 Subject: [PATCH 0240/1451] media: dt-bindings: Add OV5642 As explained in the description text from trivial-devices.yaml: "This is a list of trivial I2C and SPI devices that have simple device tree bindings, consisting only of a compatible field, an address and possibly an interrupt line." A camera device does not fall into this category as it needs other properties such as regulators, reset and powerdown GPIOs, clocks, media endpoint. Remove the OV5642 entry from trivial-devices.yaml and add its own ovti,ov5642.yaml. Signed-off-by: Fabio Estevam Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../bindings/media/i2c/ovti,ov5642.yaml | 141 ++++++++++++++++++ .../devicetree/bindings/trivial-devices.yaml | 2 - 2 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ov5642.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov5642.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov5642.yaml new file mode 100644 index 0000000000000..01f8b2b3fd172 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov5642.yaml @@ -0,0 +1,141 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/ovti,ov5642.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: OmniVision OV5642 Image Sensor + +maintainers: + - Fabio Estevam + +allOf: + - $ref: /schemas/media/video-interface-devices.yaml# + +properties: + compatible: + const: ovti,ov5642 + + reg: + maxItems: 1 + + clocks: + description: XCLK Input Clock + + AVDD-supply: + description: Analog voltage supply, 2.8V. + + DVDD-supply: + description: Digital core voltage supply, 1.5V. + + DOVDD-supply: + description: Digital I/O voltage supply, 1.8V. + + powerdown-gpios: + maxItems: 1 + description: Reference to the GPIO connected to the powerdown pin, if any. + + reset-gpios: + maxItems: 1 + description: Reference to the GPIO connected to the reset pin, if any. + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + description: | + Video output port. + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + bus-type: + enum: [5, 6] + + bus-width: + enum: [8, 10] + default: 10 + + data-shift: + enum: [0, 2] + default: 0 + + hsync-active: + enum: [0, 1] + default: 1 + + vsync-active: + enum: [0, 1] + default: 1 + + pclk-sample: + enum: [0, 1] + default: 1 + + allOf: + - if: + properties: + bus-type: + const: 6 + then: + properties: + hsync-active: false + vsync-active: false + + - if: + properties: + bus-width: + const: 10 + then: + properties: + data-shift: + const: 0 + + required: + - bus-type + + additionalProperties: false + +required: + - compatible + - reg + - clocks + - port + +additionalProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + camera@3c { + compatible = "ovti,ov5642"; + reg = <0x3c>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ov5642>; + clocks = <&clk_ext_camera>; + DOVDD-supply = <&vgen4_reg>; + AVDD-supply = <&vgen3_reg>; + DVDD-supply = <&vgen2_reg>; + powerdown-gpios = <&gpio1 19 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>; + + port { + ov5642_to_parallel: endpoint { + bus-type = ; + remote-endpoint = <¶llel_from_ov5642>; + bus-width = <8>; + data-shift = <2>; /* lines 9:2 are used */ + hsync-active = <0>; + vsync-active = <0>; + pclk-sample = <1>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index cd58179ae3379..c665018f55b94 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -311,8 +311,6 @@ properties: - nuvoton,w83773g # OKI ML86V7667 video decoder - oki,ml86v7667 - # OV5642: Color CMOS QSXGA (5-megapixel) Image Sensor with OmniBSI and Embedded TrueFocus - - ovti,ov5642 # 48-Lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch - plx,pex8648 # Pulsedlight LIDAR range-finding sensor -- GitLab From 397b2a25b8c0b66dd5e317db620eb5c72dc25827 Mon Sep 17 00:00:00 2001 From: Hao Yao Date: Fri, 15 Sep 2023 16:45:27 +0800 Subject: [PATCH 0241/1451] media: ov13b10: Add 1364x768 register settings This commit adds support for: - 1364x768 at 120 FPS Signed-off-by: Hao Yao Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov13b10.c | 58 ++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov13b10.c b/drivers/media/i2c/ov13b10.c index 8ebdb32dd3dbc..c8e0818476aba 100644 --- a/drivers/media/i2c/ov13b10.c +++ b/drivers/media/i2c/ov13b10.c @@ -31,6 +31,7 @@ #define OV13B10_REG_VTS 0x380e #define OV13B10_VTS_30FPS 0x0c7c #define OV13B10_VTS_60FPS 0x063e +#define OV13B10_VTS_120FPS 0x0320 #define OV13B10_VTS_MAX 0x7fff /* HBLANK control - read only */ @@ -468,6 +469,50 @@ static const struct ov13b10_reg mode_2080x1170_regs[] = { {0x5001, 0x0d}, }; +static const struct ov13b10_reg mode_1364x768_120fps_regs[] = { + {0x0305, 0xaf}, + {0x3011, 0x7c}, + {0x3501, 0x03}, + {0x3502, 0x00}, + {0x3662, 0x88}, + {0x3714, 0x28}, + {0x3739, 0x10}, + {0x37c2, 0x14}, + {0x37d9, 0x06}, + {0x37e2, 0x0c}, + {0x37e4, 0x00}, + {0x3800, 0x02}, + {0x3801, 0xe4}, + {0x3802, 0x03}, + {0x3803, 0x48}, + {0x3804, 0x0d}, + {0x3805, 0xab}, + {0x3806, 0x09}, + {0x3807, 0x60}, + {0x3808, 0x05}, + {0x3809, 0x54}, + {0x380a, 0x03}, + {0x380b, 0x00}, + {0x380c, 0x04}, + {0x380d, 0x8e}, + {0x380e, 0x03}, + {0x380f, 0x20}, + {0x3811, 0x07}, + {0x3813, 0x07}, + {0x3814, 0x03}, + {0x3816, 0x03}, + {0x3820, 0x8b}, + {0x3c8c, 0x18}, + {0x4008, 0x00}, + {0x4009, 0x05}, + {0x4050, 0x00}, + {0x4051, 0x05}, + {0x4501, 0x08}, + {0x4505, 0x04}, + {0x5000, 0xfd}, + {0x5001, 0x0d}, +}; + static const char * const ov13b10_test_pattern_menu[] = { "Disabled", "Vertical Color Bar Type 1", @@ -568,7 +613,18 @@ static const struct ov13b10_mode supported_modes[] = { .regs = mode_2080x1170_regs, }, .link_freq_index = OV13B10_LINK_FREQ_INDEX_0, - } + }, + { + .width = 1364, + .height = 768, + .vts_def = OV13B10_VTS_120FPS, + .vts_min = OV13B10_VTS_120FPS, + .link_freq_index = OV13B10_LINK_FREQ_INDEX_0, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1364x768_120fps_regs), + .regs = mode_1364x768_120fps_regs, + }, + }, }; struct ov13b10 { -- GitLab From 009905ec50433259c05f474251000b040098564e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 18 Sep 2023 15:48:38 +0300 Subject: [PATCH 0242/1451] media: v4l2-subdev: Document and enforce .s_stream() requirements The subdev .s_stream() operation must not be called to start an already started subdev, or stop an already stopped one. This requirement has never been formally documented. Fix it, and catch possible offenders with a WARN_ON() in the call_s_stream() wrapper. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/v4l2-core/v4l2-subdev.c | 17 ++++++++++++++++- include/media/v4l2-subdev.h | 4 +++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index b92348ad61f64..32b7d9cd43e62 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -359,6 +359,18 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable) { int ret; + /* + * The .s_stream() operation must never be called to start or stop an + * already started or stopped subdev. Catch offenders but don't return + * an error yet to avoid regressions. + * + * As .s_stream() is mutually exclusive with the .enable_streams() and + * .disable_streams() operation, we can use the enabled_streams field + * to store the subdev streaming state. + */ + if (WARN_ON(!!sd->enabled_streams == !!enable)) + return 0; + #if IS_REACHABLE(CONFIG_LEDS_CLASS) if (!IS_ERR_OR_NULL(sd->privacy_led)) { if (enable) @@ -372,9 +384,12 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable) if (!enable && ret < 0) { dev_warn(sd->dev, "disabling streaming failed (%d)\n", ret); - return 0; + ret = 0; } + if (!ret) + sd->enabled_streams = enable ? BIT(0) : 0; + return ret; } diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 820e38ec3dc91..5f59ff0796b71 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -446,7 +446,9 @@ enum v4l2_subdev_pre_streamon_flags { * @s_stream: start (enabled == 1) or stop (enabled == 0) streaming on the * sub-device. Failure on stop will remove any resources acquired in * streaming start, while the error code is still returned by the driver. - * Also see call_s_stream wrapper in v4l2-subdev.c. + * The caller shall track the subdev state, and shall not start or stop an + * already started or stopped subdev. Also see call_s_stream wrapper in + * v4l2-subdev.c. * * @g_pixelaspect: callback to return the pixelaspect ratio. * -- GitLab From 97c1151991274eed9b836a45d197093344e11173 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:09 +0300 Subject: [PATCH 0243/1451] media: i2c: hi556: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/hi556.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/i2c/hi556.c b/drivers/media/i2c/hi556.c index fd56ba1387391..2b00426c5826c 100644 --- a/drivers/media/i2c/hi556.c +++ b/drivers/media/i2c/hi556.c @@ -976,9 +976,6 @@ static int hi556_set_stream(struct v4l2_subdev *sd, int enable) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; - if (hi556->streaming == enable) - return 0; - mutex_lock(&hi556->mutex); if (enable) { ret = pm_runtime_resume_and_get(&client->dev); -- GitLab From c42995a717ec920ac9220914617358d6f6a867b2 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:10 +0300 Subject: [PATCH 0244/1451] media: i2c: hi846: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/hi846.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/i2c/hi846.c b/drivers/media/i2c/hi846.c index 8a8ae89a84539..7fbcc3ff044b7 100644 --- a/drivers/media/i2c/hi846.c +++ b/drivers/media/i2c/hi846.c @@ -1607,9 +1607,6 @@ static int hi846_set_stream(struct v4l2_subdev *sd, int enable) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; - if (hi846->streaming == enable) - return 0; - mutex_lock(&hi846->mutex); if (enable) { -- GitLab From 4d06c42942f440a3c418e2af4a02d7d00d331840 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:11 +0300 Subject: [PATCH 0245/1451] media: i2c: imx208: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx208.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/i2c/imx208.c b/drivers/media/i2c/imx208.c index a6edcae4ef47e..e5c2b47528329 100644 --- a/drivers/media/i2c/imx208.c +++ b/drivers/media/i2c/imx208.c @@ -714,10 +714,6 @@ static int imx208_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; mutex_lock(&imx208->imx208_mx); - if (imx208->streaming == enable) { - mutex_unlock(&imx208->imx208_mx); - return 0; - } if (enable) { ret = pm_runtime_resume_and_get(&client->dev); -- GitLab From f35675411bbe239201f1c962fa16f30b5003c28a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:12 +0300 Subject: [PATCH 0246/1451] media: i2c: imx214: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. Signed-off-by: Laurent Pinchart Reviewed-by: Ricardo Ribalda Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx214.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c index 2f9c8582f9401..e2805173f4b1a 100644 --- a/drivers/media/i2c/imx214.c +++ b/drivers/media/i2c/imx214.c @@ -775,9 +775,6 @@ static int imx214_s_stream(struct v4l2_subdev *subdev, int enable) struct imx214 *imx214 = to_imx214(subdev); int ret; - if (imx214->streaming == enable) - return 0; - if (enable) { ret = pm_runtime_resume_and_get(imx214->dev); if (ret < 0) -- GitLab From fcf877f19165dadb2e0c9e631b4cb7027f24ec86 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:13 +0300 Subject: [PATCH 0247/1451] media: i2c: imx219: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. Signed-off-by: Laurent Pinchart Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index ec53abe2e84e5..e247e46db6c04 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -980,9 +980,6 @@ static int imx219_set_stream(struct v4l2_subdev *sd, int enable) state = v4l2_subdev_lock_and_get_active_state(sd); - if (imx219->streaming == enable) - goto unlock; - if (enable) { /* * Apply default & customized values -- GitLab From 9c5ab9574fa18d497abddca323e42ea9b00c6c15 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:14 +0300 Subject: [PATCH 0248/1451] media: i2c: imx258: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx258.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c index e196565e846e6..4be0422b7cdac 100644 --- a/drivers/media/i2c/imx258.c +++ b/drivers/media/i2c/imx258.c @@ -1035,10 +1035,6 @@ static int imx258_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; mutex_lock(&imx258->mutex); - if (imx258->streaming == enable) { - mutex_unlock(&imx258->mutex); - return 0; - } if (enable) { ret = pm_runtime_resume_and_get(&client->dev); -- GitLab From 1cbdd6659b2ac70a1188dab9ea56d58dba71ee12 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:15 +0300 Subject: [PATCH 0249/1451] media: i2c: imx319: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx319.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/i2c/imx319.c b/drivers/media/i2c/imx319.c index 52ebb096e1075..935bcbacd62e1 100644 --- a/drivers/media/i2c/imx319.c +++ b/drivers/media/i2c/imx319.c @@ -2166,10 +2166,6 @@ static int imx319_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; mutex_lock(&imx319->mutex); - if (imx319->streaming == enable) { - mutex_unlock(&imx319->mutex); - return 0; - } if (enable) { ret = pm_runtime_resume_and_get(&client->dev); -- GitLab From 5a6e2fc7d018c32136dbc05f7fa66b5b91b25ffa Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:16 +0300 Subject: [PATCH 0250/1451] media: i2c: imx334: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx334.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/media/i2c/imx334.c b/drivers/media/i2c/imx334.c index 91c79af70734f..1196fe93506bd 100644 --- a/drivers/media/i2c/imx334.c +++ b/drivers/media/i2c/imx334.c @@ -138,7 +138,6 @@ struct imx334_mode { * @mutex: Mutex for serializing sensor controls * @menu_skip_mask: Menu skip mask for link_freq_ctrl * @cur_code: current selected format code - * @streaming: Flag indicating streaming state */ struct imx334 { struct device *dev; @@ -161,7 +160,6 @@ struct imx334 { struct mutex mutex; unsigned long menu_skip_mask; u32 cur_code; - bool streaming; }; static const s64 link_freq[] = { @@ -1051,11 +1049,6 @@ static int imx334_set_stream(struct v4l2_subdev *sd, int enable) mutex_lock(&imx334->mutex); - if (imx334->streaming == enable) { - mutex_unlock(&imx334->mutex); - return 0; - } - if (enable) { ret = pm_runtime_resume_and_get(imx334->dev); if (ret < 0) @@ -1069,8 +1062,6 @@ static int imx334_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(imx334->dev); } - imx334->streaming = enable; - mutex_unlock(&imx334->mutex); return 0; -- GitLab From ee44330bf068eaca358ba474ac525264e78ec3fd Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:17 +0300 Subject: [PATCH 0251/1451] media: i2c: imx335: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx335.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c index 482a0b7f040a5..ec729126274b2 100644 --- a/drivers/media/i2c/imx335.c +++ b/drivers/media/i2c/imx335.c @@ -119,7 +119,6 @@ struct imx335_mode { * @vblank: Vertical blanking in lines * @cur_mode: Pointer to current selected sensor mode * @mutex: Mutex for serializing sensor controls - * @streaming: Flag indicating streaming state */ struct imx335 { struct device *dev; @@ -140,7 +139,6 @@ struct imx335 { u32 vblank; const struct imx335_mode *cur_mode; struct mutex mutex; - bool streaming; }; static const s64 link_freq[] = { @@ -705,11 +703,6 @@ static int imx335_set_stream(struct v4l2_subdev *sd, int enable) mutex_lock(&imx335->mutex); - if (imx335->streaming == enable) { - mutex_unlock(&imx335->mutex); - return 0; - } - if (enable) { ret = pm_runtime_resume_and_get(imx335->dev); if (ret) @@ -723,8 +716,6 @@ static int imx335_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(imx335->dev); } - imx335->streaming = enable; - mutex_unlock(&imx335->mutex); return 0; -- GitLab From 972ba0bcac67397a71205e60c18d358efc7ec748 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:18 +0300 Subject: [PATCH 0252/1451] media: i2c: imx355: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx355.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c index 9c79ae8dc8428..43c09941704e9 100644 --- a/drivers/media/i2c/imx355.c +++ b/drivers/media/i2c/imx355.c @@ -1436,10 +1436,6 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; mutex_lock(&imx355->mutex); - if (imx355->streaming == enable) { - mutex_unlock(&imx355->mutex); - return 0; - } if (enable) { ret = pm_runtime_resume_and_get(&client->dev); -- GitLab From bf5c004691d19adb900044f0696c4d1156881747 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:19 +0300 Subject: [PATCH 0253/1451] media: i2c: imx412: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx412.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c index c7e862ae4040f..962b3136c31ee 100644 --- a/drivers/media/i2c/imx412.c +++ b/drivers/media/i2c/imx412.c @@ -127,7 +127,6 @@ static const char * const imx412_supply_names[] = { * @vblank: Vertical blanking in lines * @cur_mode: Pointer to current selected sensor mode * @mutex: Mutex for serializing sensor controls - * @streaming: Flag indicating streaming state */ struct imx412 { struct device *dev; @@ -149,7 +148,6 @@ struct imx412 { u32 vblank; const struct imx412_mode *cur_mode; struct mutex mutex; - bool streaming; }; static const s64 link_freq[] = { @@ -857,11 +855,6 @@ static int imx412_set_stream(struct v4l2_subdev *sd, int enable) mutex_lock(&imx412->mutex); - if (imx412->streaming == enable) { - mutex_unlock(&imx412->mutex); - return 0; - } - if (enable) { ret = pm_runtime_resume_and_get(imx412->dev); if (ret) @@ -875,8 +868,6 @@ static int imx412_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(imx412->dev); } - imx412->streaming = enable; - mutex_unlock(&imx412->mutex); return 0; -- GitLab From 8beaae2c2bf05e312f4b2434e334e8a44e499032 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:20 +0300 Subject: [PATCH 0254/1451] media: i2c: mt9m001: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/mt9m001.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c index ce9568e8391cd..79192cf79d287 100644 --- a/drivers/media/i2c/mt9m001.c +++ b/drivers/media/i2c/mt9m001.c @@ -93,7 +93,6 @@ struct mt9m001 { struct v4l2_ctrl *autoexposure; struct v4l2_ctrl *exposure; }; - bool streaming; struct mutex mutex; struct v4l2_rect rect; /* Sensor window */ struct clk *clk; @@ -213,9 +212,6 @@ static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable) mutex_lock(&mt9m001->mutex); - if (mt9m001->streaming == enable) - goto done; - if (enable) { ret = pm_runtime_resume_and_get(&client->dev); if (ret < 0) @@ -239,8 +235,6 @@ static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - mt9m001->streaming = enable; -done: mutex_unlock(&mt9m001->mutex); return 0; -- GitLab From 062361fc6c84e457778f2f80aa26b2d504d3fe21 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:21 +0300 Subject: [PATCH 0255/1451] media: i2c: og01a1b: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/og01a1b.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/i2c/og01a1b.c b/drivers/media/i2c/og01a1b.c index ccf6731ea2e22..956ad3e996b64 100644 --- a/drivers/media/i2c/og01a1b.c +++ b/drivers/media/i2c/og01a1b.c @@ -732,9 +732,6 @@ static int og01a1b_set_stream(struct v4l2_subdev *sd, int enable) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; - if (og01a1b->streaming == enable) - return 0; - mutex_lock(&og01a1b->mutex); if (enable) { ret = pm_runtime_resume_and_get(&client->dev); -- GitLab From 608e0f10bfb903d15a936f02a4d6ca752347dd3c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:22 +0300 Subject: [PATCH 0256/1451] media: i2c: ov01a10: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov01a10.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/i2c/ov01a10.c b/drivers/media/i2c/ov01a10.c index 2b9e1b3a3bf4f..b43c1c96f47bc 100644 --- a/drivers/media/i2c/ov01a10.c +++ b/drivers/media/i2c/ov01a10.c @@ -672,8 +672,6 @@ static int ov01a10_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; state = v4l2_subdev_lock_and_get_active_state(sd); - if (ov01a10->streaming == enable) - goto unlock; if (enable) { ret = pm_runtime_resume_and_get(&client->dev); -- GitLab From 51d5de9da3be1d5b615183223c559a95ee4710c5 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:23 +0300 Subject: [PATCH 0257/1451] media: i2c: ov08d10: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov08d10.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/i2c/ov08d10.c b/drivers/media/i2c/ov08d10.c index 7d55d4ca24de1..ef811711549cf 100644 --- a/drivers/media/i2c/ov08d10.c +++ b/drivers/media/i2c/ov08d10.c @@ -1103,9 +1103,6 @@ static int ov08d10_set_stream(struct v4l2_subdev *sd, int enable) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; - if (ov08d10->streaming == enable) - return 0; - mutex_lock(&ov08d10->mutex); if (enable) { ret = pm_runtime_resume_and_get(&client->dev); -- GitLab From a0caba4916af26ae992141f98a9eb340efb47730 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:24 +0300 Subject: [PATCH 0258/1451] media: i2c: ov08x40: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov08x40.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/i2c/ov08x40.c b/drivers/media/i2c/ov08x40.c index 637da4df69011..1ea402550837b 100644 --- a/drivers/media/i2c/ov08x40.c +++ b/drivers/media/i2c/ov08x40.c @@ -2915,10 +2915,6 @@ static int ov08x40_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; mutex_lock(&ov08x->mutex); - if (ov08x->streaming == enable) { - mutex_unlock(&ov08x->mutex); - return 0; - } if (enable) { ret = pm_runtime_resume_and_get(&client->dev); -- GitLab From 70096d41d02b94b8eeb143b989ab590f009c9ccb Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:25 +0300 Subject: [PATCH 0259/1451] media: i2c: ov13858: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov13858.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index 35652b3623472..b90ce338a47a9 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -1467,10 +1467,6 @@ static int ov13858_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; mutex_lock(&ov13858->mutex); - if (ov13858->streaming == enable) { - mutex_unlock(&ov13858->mutex); - return 0; - } if (enable) { ret = pm_runtime_resume_and_get(&client->dev); -- GitLab From acc53ef65cab23b02918da8806d387dbc4045683 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:26 +0300 Subject: [PATCH 0260/1451] media: i2c: ov13b10: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov13b10.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/i2c/ov13b10.c b/drivers/media/i2c/ov13b10.c index c8e0818476aba..32c598ed77522 100644 --- a/drivers/media/i2c/ov13b10.c +++ b/drivers/media/i2c/ov13b10.c @@ -1217,10 +1217,6 @@ static int ov13b10_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; mutex_lock(&ov13b->mutex); - if (ov13b->streaming == enable) { - mutex_unlock(&ov13b->mutex); - return 0; - } if (enable) { ret = pm_runtime_resume_and_get(&client->dev); -- GitLab From 493d786bd87dbb92d8051fae7ab5505650b805f9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:27 +0300 Subject: [PATCH 0261/1451] media: i2c: ov2685: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov2685.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c index de0d34e43969f..396583826ae91 100644 --- a/drivers/media/i2c/ov2685.c +++ b/drivers/media/i2c/ov2685.c @@ -91,7 +91,6 @@ struct ov2685 { struct gpio_desc *reset_gpio; struct regulator_bulk_data supplies[OV2685_NUM_SUPPLIES]; - bool streaming; struct mutex mutex; struct v4l2_subdev subdev; struct media_pad pad; @@ -513,10 +512,6 @@ static int ov2685_s_stream(struct v4l2_subdev *sd, int on) mutex_lock(&ov2685->mutex); - on = !!on; - if (on == ov2685->streaming) - goto unlock_and_return; - if (on) { ret = pm_runtime_resume_and_get(&ov2685->client->dev); if (ret < 0) @@ -539,8 +534,6 @@ static int ov2685_s_stream(struct v4l2_subdev *sd, int on) pm_runtime_put(&ov2685->client->dev); } - ov2685->streaming = on; - unlock_and_return: mutex_unlock(&ov2685->mutex); -- GitLab From 58e7ab2f381b06e9eb212fc9ba4d2f1cef4181b0 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:28 +0300 Subject: [PATCH 0262/1451] media: i2c: ov2740: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov2740.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index 41d4f85470fd2..59356dd9afd81 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -794,9 +794,6 @@ static int ov2740_set_stream(struct v4l2_subdev *sd, int enable) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; - if (ov2740->streaming == enable) - return 0; - mutex_lock(&ov2740->mutex); if (enable) { ret = pm_runtime_resume_and_get(&client->dev); -- GitLab From e8d6eb9a9b8dcf050e345ebe7edc31691c73f608 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:29 +0300 Subject: [PATCH 0263/1451] media: i2c: ov4689: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Reviewed-by: Mikhail Rudenko [Sakari Ailus: remove now-redundant "streaming" from comment.] Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov4689.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/media/i2c/ov4689.c b/drivers/media/i2c/ov4689.c index fda217d2cb10a..3bd972a822e7b 100644 --- a/drivers/media/i2c/ov4689.c +++ b/drivers/media/i2c/ov4689.c @@ -99,8 +99,7 @@ struct ov4689 { u32 clock_rate; - struct mutex mutex; /* lock to protect streaming, ctrls and cur_mode */ - bool streaming; + struct mutex mutex; /* lock to protect ctrls and cur_mode */ struct v4l2_ctrl_handler ctrl_handler; struct v4l2_ctrl *exposure; @@ -468,10 +467,6 @@ static int ov4689_s_stream(struct v4l2_subdev *sd, int on) mutex_lock(&ov4689->mutex); - on = !!on; - if (on == ov4689->streaming) - goto unlock_and_return; - if (on) { ret = pm_runtime_resume_and_get(&client->dev); if (ret < 0) @@ -504,8 +499,6 @@ static int ov4689_s_stream(struct v4l2_subdev *sd, int on) pm_runtime_put(&client->dev); } - ov4689->streaming = on; - unlock_and_return: mutex_unlock(&ov4689->mutex); -- GitLab From 444a94daac36c4cb3133af42d8f170ce15ab4138 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:30 +0300 Subject: [PATCH 0264/1451] media: i2c: ov5647: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov5647.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c index 8de398423b7cb..dcfe3129c63ac 100644 --- a/drivers/media/i2c/ov5647.c +++ b/drivers/media/i2c/ov5647.c @@ -109,7 +109,6 @@ struct ov5647 { struct v4l2_ctrl *hblank; struct v4l2_ctrl *vblank; struct v4l2_ctrl *exposure; - bool streaming; }; static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd) @@ -898,10 +897,6 @@ static int ov5647_s_stream(struct v4l2_subdev *sd, int enable) int ret; mutex_lock(&sensor->lock); - if (sensor->streaming == enable) { - mutex_unlock(&sensor->lock); - return 0; - } if (enable) { ret = pm_runtime_resume_and_get(&client->dev); @@ -922,7 +917,6 @@ static int ov5647_s_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - sensor->streaming = enable; mutex_unlock(&sensor->lock); return 0; -- GitLab From 33e9cdc325b7121f33c7dd1184ea5dd62e770201 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:31 +0300 Subject: [PATCH 0265/1451] media: i2c: ov5670: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov5670.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index 29e773a997dd4..afd84c8e5ee79 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -2471,8 +2471,6 @@ static int ov5670_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; mutex_lock(&ov5670->mutex); - if (ov5670->streaming == enable) - goto unlock_and_return; if (enable) { ret = pm_runtime_resume_and_get(&client->dev); -- GitLab From 1b59508e0ba66dfebf0e716eafc34dbaca966488 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:32 +0300 Subject: [PATCH 0266/1451] media: i2c: ov5675: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov5675.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c index d5a2a5f823124..f608ee0c0cec4 100644 --- a/drivers/media/i2c/ov5675.c +++ b/drivers/media/i2c/ov5675.c @@ -949,9 +949,6 @@ static int ov5675_set_stream(struct v4l2_subdev *sd, int enable) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; - if (ov5675->streaming == enable) - return 0; - mutex_lock(&ov5675->mutex); if (enable) { ret = pm_runtime_resume_and_get(&client->dev); -- GitLab From 3ca1480abdd93b6f7559720794db8527288abc56 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:33 +0300 Subject: [PATCH 0267/1451] media: i2c: ov5695: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov5695.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c index 8d1c3a673c23a..c8f57ce1578dc 100644 --- a/drivers/media/i2c/ov5695.c +++ b/drivers/media/i2c/ov5695.c @@ -108,7 +108,6 @@ struct ov5695 { struct v4l2_ctrl *vblank; struct v4l2_ctrl *test_pattern; struct mutex mutex; - bool streaming; const struct ov5695_mode *cur_mode; }; @@ -935,9 +934,6 @@ static int ov5695_s_stream(struct v4l2_subdev *sd, int on) int ret = 0; mutex_lock(&ov5695->mutex); - on = !!on; - if (on == ov5695->streaming) - goto unlock_and_return; if (on) { ret = pm_runtime_resume_and_get(&client->dev); @@ -955,8 +951,6 @@ static int ov5695_s_stream(struct v4l2_subdev *sd, int on) pm_runtime_put(&client->dev); } - ov5695->streaming = on; - unlock_and_return: mutex_unlock(&ov5695->mutex); -- GitLab From f29f0a98f223c44fe919124ef46ad95d2444193a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:34 +0300 Subject: [PATCH 0268/1451] media: i2c: ov7740: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov7740.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index 78d04ce68971a..356a45e65b81b 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -118,7 +118,6 @@ struct ov7740 { struct v4l2_ctrl *contrast; struct mutex mutex; /* To serialize asynchronus callbacks */ - bool streaming; /* Streaming on/off */ struct gpio_desc *resetb_gpio; struct gpio_desc *pwdn_gpio; @@ -616,10 +615,6 @@ static int ov7740_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; mutex_lock(&ov7740->mutex); - if (ov7740->streaming == enable) { - mutex_unlock(&ov7740->mutex); - return 0; - } if (enable) { ret = pm_runtime_resume_and_get(&client->dev); @@ -633,8 +628,6 @@ static int ov7740_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - ov7740->streaming = enable; - mutex_unlock(&ov7740->mutex); return ret; -- GitLab From 741358bb85578d49601b8a1c085da1b63d7a0f85 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:35 +0300 Subject: [PATCH 0269/1451] media: i2c: ov8856: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov8856.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index f053c3a7676a0..5447a33619762 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -2042,9 +2042,6 @@ static int ov8856_set_stream(struct v4l2_subdev *sd, int enable) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; - if (ov8856->streaming == enable) - return 0; - mutex_lock(&ov8856->mutex); if (enable) { ret = pm_runtime_resume_and_get(&client->dev); -- GitLab From 36cb37a69ebd61d0e6acf1db05d2b17077014f1b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:36 +0300 Subject: [PATCH 0270/1451] media: i2c: ov9282: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov9282.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c index 068c7449f50ed..bf6dfce1b5dd8 100644 --- a/drivers/media/i2c/ov9282.c +++ b/drivers/media/i2c/ov9282.c @@ -165,7 +165,6 @@ struct ov9282_mode { * @cur_mode: Pointer to current selected sensor mode * @code: Mbus code currently selected * @mutex: Mutex for serializing sensor controls - * @streaming: Flag indicating streaming state */ struct ov9282 { struct device *dev; @@ -188,7 +187,6 @@ struct ov9282 { const struct ov9282_mode *cur_mode; u32 code; struct mutex mutex; - bool streaming; }; static const s64 link_freq[] = { @@ -1037,11 +1035,6 @@ static int ov9282_set_stream(struct v4l2_subdev *sd, int enable) mutex_lock(&ov9282->mutex); - if (ov9282->streaming == enable) { - mutex_unlock(&ov9282->mutex); - return 0; - } - if (enable) { ret = pm_runtime_resume_and_get(ov9282->dev); if (ret) @@ -1055,8 +1048,6 @@ static int ov9282_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(ov9282->dev); } - ov9282->streaming = enable; - mutex_unlock(&ov9282->mutex); return 0; -- GitLab From f765cc2913c0fea9820bfcfef783992d34d250c9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:37 +0300 Subject: [PATCH 0271/1451] media: i2c: ov9734: Drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov9734.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/i2c/ov9734.c b/drivers/media/i2c/ov9734.c index b6244772bc593..a5f91499bce49 100644 --- a/drivers/media/i2c/ov9734.c +++ b/drivers/media/i2c/ov9734.c @@ -660,10 +660,6 @@ static int ov9734_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; mutex_lock(&ov9734->mutex); - if (ov9734->streaming == enable) { - mutex_unlock(&ov9734->mutex); - return 0; - } if (enable) { ret = pm_runtime_resume_and_get(&client->dev); -- GitLab From 8c547f9b3e641332a5c06454d03f7de6e5acda7e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:38 +0300 Subject: [PATCH 0272/1451] Documentation: media: camera-sensor: Fix typo and vocabulary selection Drop an unneeded double colon, and use 'shall' instead of 'must' for consistency with the rest of the file. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- Documentation/driver-api/media/camera-sensor.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/driver-api/media/camera-sensor.rst b/Documentation/driver-api/media/camera-sensor.rst index 93f4f2536c250..96cfbc261b6e6 100644 --- a/Documentation/driver-api/media/camera-sensor.rst +++ b/Documentation/driver-api/media/camera-sensor.rst @@ -13,7 +13,7 @@ Handling clocks Camera sensors have an internal clock tree including a PLL and a number of divisors. The clock tree is generally configured by the driver based on a few -input parameters that are specific to the hardware:: the external clock frequency +input parameters that are specific to the hardware: the external clock frequency and the link frequency. The two parameters generally are obtained from system firmware. **No other frequencies should be used in any circumstances.** @@ -123,7 +123,7 @@ Power management Always use runtime PM to manage the power states of your device. Camera sensor drivers are in no way special in this respect: they are responsible for controlling the power state of the device they otherwise control as well. In -general, the device must be powered on at least when its registers are being +general, the device shall be powered on at least when its registers are being accessed and when it is streaming. Existing camera sensor drivers may rely on the old -- GitLab From 6d032832b1ffa0f6933bb99dd3d1461763025ed4 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:39 +0300 Subject: [PATCH 0273/1451] Documentation: media: camera-sensor: Use link to upstream DT bindings The Documentation/devicetree/bindings/clock/clock-bindings.txt file is deprecated and points to clock-bindings.yaml, which is not hosted in the kernel source tree. Use an HTTPS link to refer to the YAML binding document. While at it, drop "currently" from the paragraph, as the whole file refers to the current recommended practices except where explicitly noted. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- Documentation/driver-api/media/camera-sensor.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Documentation/driver-api/media/camera-sensor.rst b/Documentation/driver-api/media/camera-sensor.rst index 96cfbc261b6e6..3510a57ecb9ae 100644 --- a/Documentation/driver-api/media/camera-sensor.rst +++ b/Documentation/driver-api/media/camera-sensor.rst @@ -32,10 +32,11 @@ can rely on this frequency being used. Devicetree ~~~~~~~~~~ -The currently preferred way to achieve this is using ``assigned-clocks``, -``assigned-clock-parents`` and ``assigned-clock-rates`` properties. See -``Documentation/devicetree/bindings/clock/clock-bindings.txt`` for more -information. The driver then gets the frequency using ``clk_get_rate()``. +The preferred way to achieve this is using ``assigned-clocks``, +``assigned-clock-parents`` and ``assigned-clock-rates`` properties. See the +`clock device tree bindings `_ +for more information. The driver then gets the frequency using +``clk_get_rate()``. This approach has the drawback that there's no guarantee that the frequency hasn't been modified directly or indirectly by another driver, or supported by -- GitLab From f13734b5071751bc2093c4cc4ada88e585cfa797 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:40 +0300 Subject: [PATCH 0274/1451] Documentation: media: camera-sensor: Move power management section Move the power management section up, just after clocks, as it relates to internal system resources and not features exposed to applications. The text itself is otherwise unchanged. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../driver-api/media/camera-sensor.rst | 70 +++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/Documentation/driver-api/media/camera-sensor.rst b/Documentation/driver-api/media/camera-sensor.rst index 3510a57ecb9ae..8ab166a2138d6 100644 --- a/Documentation/driver-api/media/camera-sensor.rst +++ b/Documentation/driver-api/media/camera-sensor.rst @@ -43,6 +43,41 @@ hasn't been modified directly or indirectly by another driver, or supported by the board's clock tree to begin with. Changes to the Common Clock Framework API are required to ensure reliability. +Power management +---------------- + +Always use runtime PM to manage the power states of your device. Camera sensor +drivers are in no way special in this respect: they are responsible for +controlling the power state of the device they otherwise control as well. In +general, the device shall be powered on at least when its registers are being +accessed and when it is streaming. + +Existing camera sensor drivers may rely on the old +struct v4l2_subdev_core_ops->s_power() callback for bridge or ISP drivers to +manage their power state. This is however **deprecated**. If you feel you need +to begin calling an s_power from an ISP or a bridge driver, instead please add +runtime PM support to the sensor driver you are using. Likewise, new drivers +should not use s_power. + +Please see examples in e.g. ``drivers/media/i2c/ov8856.c`` and +``drivers/media/i2c/ccs/ccs-core.c``. The two drivers work in both ACPI +and DT based systems. + +Control framework +~~~~~~~~~~~~~~~~~ + +``v4l2_ctrl_handler_setup()`` function may not be used in the device's runtime +PM ``runtime_resume`` callback, as it has no way to figure out the power state +of the device. This is because the power state of the device is only changed +after the power state transition has taken place. The ``s_ctrl`` callback can be +used to obtain device's power state after the power state transition: + +.. c:function:: int pm_runtime_get_if_in_use(struct device *dev); + +The function returns a non-zero value if it succeeded getting the power count or +runtime PM was disabled, in either of which cases the driver may proceed to +access the device. + Frame size ---------- @@ -118,41 +153,6 @@ rate) on device level in firmware or hardware. This means lower level controls implemented by raw cameras may not be used on uAPI (or even kAPI) to control the frame interval on these devices. -Power management ----------------- - -Always use runtime PM to manage the power states of your device. Camera sensor -drivers are in no way special in this respect: they are responsible for -controlling the power state of the device they otherwise control as well. In -general, the device shall be powered on at least when its registers are being -accessed and when it is streaming. - -Existing camera sensor drivers may rely on the old -struct v4l2_subdev_core_ops->s_power() callback for bridge or ISP drivers to -manage their power state. This is however **deprecated**. If you feel you need -to begin calling an s_power from an ISP or a bridge driver, instead please add -runtime PM support to the sensor driver you are using. Likewise, new drivers -should not use s_power. - -Please see examples in e.g. ``drivers/media/i2c/ov8856.c`` and -``drivers/media/i2c/ccs/ccs-core.c``. The two drivers work in both ACPI -and DT based systems. - -Control framework -~~~~~~~~~~~~~~~~~ - -``v4l2_ctrl_handler_setup()`` function may not be used in the device's runtime -PM ``runtime_resume`` callback, as it has no way to figure out the power state -of the device. This is because the power state of the device is only changed -after the power state transition has taken place. The ``s_ctrl`` callback can be -used to obtain device's power state after the power state transition: - -.. c:function:: int pm_runtime_get_if_in_use(struct device *dev); - -The function returns a non-zero value if it succeeded getting the power count or -runtime PM was disabled, in either of which cases the driver may proceed to -access the device. - Rotation, orientation and flipping ---------------------------------- -- GitLab From 7610bfe723650c4c34bd9eb59d389975150a6c5b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:41 +0300 Subject: [PATCH 0275/1451] Documentation: media: camera-sensor: Improve power management documentation Camera sensor drivers are highly subject to cargo cult programming, with back practices being copied from old to new drivers. In particular, many drivers implement system and runtime PM incorrectly. As a first step towards fixing this situation, refactor and expand the power management documentation to detail correct usage of system and runtime PM. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../driver-api/media/camera-sensor.rst | 58 ++++++++++++++----- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/Documentation/driver-api/media/camera-sensor.rst b/Documentation/driver-api/media/camera-sensor.rst index 8ab166a2138d6..2acc08142a1a5 100644 --- a/Documentation/driver-api/media/camera-sensor.rst +++ b/Documentation/driver-api/media/camera-sensor.rst @@ -46,22 +46,48 @@ are required to ensure reliability. Power management ---------------- -Always use runtime PM to manage the power states of your device. Camera sensor -drivers are in no way special in this respect: they are responsible for -controlling the power state of the device they otherwise control as well. In -general, the device shall be powered on at least when its registers are being -accessed and when it is streaming. - -Existing camera sensor drivers may rely on the old -struct v4l2_subdev_core_ops->s_power() callback for bridge or ISP drivers to -manage their power state. This is however **deprecated**. If you feel you need -to begin calling an s_power from an ISP or a bridge driver, instead please add -runtime PM support to the sensor driver you are using. Likewise, new drivers -should not use s_power. - -Please see examples in e.g. ``drivers/media/i2c/ov8856.c`` and -``drivers/media/i2c/ccs/ccs-core.c``. The two drivers work in both ACPI -and DT based systems. +Camera sensors are used in conjunction with other devices to form a camera +pipeline. They must obey the rules listed herein to ensure coherent power +management over the pipeline. + +Camera sensor drivers are responsible for controlling the power state of the +device they otherwise control as well. They shall use runtime PM to manage +power states. Runtime PM shall be enabled at probe time and disabled at remove +time. Drivers should enable runtime PM autosuspend. + +The runtime PM handlers shall handle clocks, regulators, GPIOs, and other +system resources required to power the sensor up and down. For drivers that +don't use any of those resources (such as drivers that support ACPI systems +only), the runtime PM handlers may be left unimplemented. + +In general, the device shall be powered on at least when its registers are +being accessed and when it is streaming. Drivers should use +``pm_runtime_resume_and_get()`` when starting streaming and +``pm_runtime_put()`` or ``pm_runtime_put_autosuspend()`` when stopping +streaming. They may power the device up at probe time (for example to read +identification registers), but should not keep it powered unconditionally after +probe. + +At system suspend time, the whole camera pipeline must stop streaming, and +restart when the system is resumed. This requires coordination between the +camera sensor and the rest of the camera pipeline. Bridge drivers are +responsible for this coordination, and instruct camera sensors to stop and +restart streaming by calling the appropriate subdev operations +(``.s_stream()``, ``.enable_streams()`` or ``.disable_streams()``). Camera +sensor drivers shall therefore **not** keep track of the streaming state to +stop streaming in the PM suspend handler and restart it in the resume handler. +Drivers should in general not implement the system PM handlers. + +Camera sensor drivers shall **not** implement the subdev ``.s_power()`` +operation, as it is deprecated. While this operation is implemented in some +existing drivers as they predate the deprecation, new drivers shall use runtime +PM instead. If you feel you need to begin calling ``.s_power()`` from an ISP or +a bridge driver, instead add runtime PM support to the sensor driver you are +using and drop its ``.s_power()`` handler. + +See examples of runtime PM handling in e.g. ``drivers/media/i2c/ov8856.c`` and +``drivers/media/i2c/ccs/ccs-core.c``. The two drivers work in both ACPI and DT +based systems. Control framework ~~~~~~~~~~~~~~~~~ -- GitLab From 8c1e33818003183890bba78c0cabbf203846f85a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:42 +0300 Subject: [PATCH 0276/1451] media: i2c: ar0521: Drop system suspend and resume handlers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Acked-by: Krzysztof Hałasa Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ar0521.c | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c index a4e39871e8f75..701f36345f1e7 100644 --- a/drivers/media/i2c/ar0521.c +++ b/drivers/media/i2c/ar0521.c @@ -133,8 +133,6 @@ struct ar0521_dev { u16 mult2; u16 vt_pix; } pll; - - bool streaming; }; static inline struct ar0521_dev *to_ar0521_dev(struct v4l2_subdev *sd) @@ -991,12 +989,9 @@ static int ar0521_s_stream(struct v4l2_subdev *sd, int enable) int ret; mutex_lock(&sensor->lock); - ret = ar0521_set_stream(sensor, enable); - if (!ret) - sensor->streaming = enable; - mutex_unlock(&sensor->lock); + return ret; } @@ -1023,28 +1018,6 @@ static const struct v4l2_subdev_ops ar0521_subdev_ops = { .pad = &ar0521_pad_ops, }; -static int __maybe_unused ar0521_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ar0521_dev *sensor = to_ar0521_dev(sd); - - if (sensor->streaming) - ar0521_set_stream(sensor, 0); - - return 0; -} - -static int __maybe_unused ar0521_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ar0521_dev *sensor = to_ar0521_dev(sd); - - if (sensor->streaming) - return ar0521_set_stream(sensor, 1); - - return 0; -} - static int ar0521_probe(struct i2c_client *client) { struct v4l2_fwnode_endpoint ep = { @@ -1183,7 +1156,6 @@ static void ar0521_remove(struct i2c_client *client) } static const struct dev_pm_ops ar0521_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ar0521_suspend, ar0521_resume) SET_RUNTIME_PM_OPS(ar0521_power_off, ar0521_power_on, NULL) }; static const struct of_device_id ar0521_dt_ids[] = { -- GitLab From 2c13a5ad0426e64cc30da41af580bbfbb58f55d8 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:43 +0300 Subject: [PATCH 0277/1451] media: i2c: ccs: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ccs/ccs-core.c | 37 -------------------------------- 1 file changed, 37 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 569bf9b67539a..6a8116454f877 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -3152,42 +3152,6 @@ static const struct v4l2_subdev_internal_ops ccs_internal_ops = { * I2C Driver */ -static int __maybe_unused ccs_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - bool streaming = sensor->streaming; - int rval; - - rval = pm_runtime_resume_and_get(dev); - if (rval < 0) - return rval; - - if (sensor->streaming) - ccs_stop_streaming(sensor); - - /* save state for resume */ - sensor->streaming = streaming; - - return 0; -} - -static int __maybe_unused ccs_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - int rval = 0; - - pm_runtime_put(dev); - - if (sensor->streaming) - rval = ccs_start_streaming(sensor); - - return rval; -} - static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev) { struct ccs_hwconfig *hwcfg = &sensor->hwcfg; @@ -3720,7 +3684,6 @@ static const struct of_device_id ccs_of_table[] = { MODULE_DEVICE_TABLE(of, ccs_of_table); static const struct dev_pm_ops ccs_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ccs_suspend, ccs_resume) SET_RUNTIME_PM_OPS(ccs_power_off, ccs_power_on, NULL) }; -- GitLab From 5d821eb21f431724237c0d7c25816d92b7b1e857 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:44 +0300 Subject: [PATCH 0278/1451] media: i2c: hi556: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/hi556.c | 47 --------------------------------------- 1 file changed, 47 deletions(-) diff --git a/drivers/media/i2c/hi556.c b/drivers/media/i2c/hi556.c index 2b00426c5826c..e6e7049108e75 100644 --- a/drivers/media/i2c/hi556.c +++ b/drivers/media/i2c/hi556.c @@ -577,9 +577,6 @@ struct hi556 { /* To serialize asynchronus callbacks */ struct mutex mutex; - /* Streaming on/off */ - bool streaming; - /* True if the device has been identified */ bool identified; }; @@ -995,50 +992,11 @@ static int hi556_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - hi556->streaming = enable; mutex_unlock(&hi556->mutex); return ret; } -static int __maybe_unused hi556_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct hi556 *hi556 = to_hi556(sd); - - mutex_lock(&hi556->mutex); - if (hi556->streaming) - hi556_stop_streaming(hi556); - - mutex_unlock(&hi556->mutex); - - return 0; -} - -static int __maybe_unused hi556_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct hi556 *hi556 = to_hi556(sd); - int ret; - - mutex_lock(&hi556->mutex); - if (hi556->streaming) { - ret = hi556_start_streaming(hi556); - if (ret) - goto error; - } - - mutex_unlock(&hi556->mutex); - - return 0; - -error: - hi556_stop_streaming(hi556); - hi556->streaming = 0; - mutex_unlock(&hi556->mutex); - return ret; -} - static int hi556_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -1328,10 +1286,6 @@ static int hi556_probe(struct i2c_client *client) return ret; } -static const struct dev_pm_ops hi556_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(hi556_suspend, hi556_resume) -}; - #ifdef CONFIG_ACPI static const struct acpi_device_id hi556_acpi_ids[] = { {"INT3537"}, @@ -1344,7 +1298,6 @@ MODULE_DEVICE_TABLE(acpi, hi556_acpi_ids); static struct i2c_driver hi556_i2c_driver = { .driver = { .name = "hi556", - .pm = &hi556_pm_ops, .acpi_match_table = ACPI_PTR(hi556_acpi_ids), }, .probe = hi556_probe, -- GitLab From 2223243cdfc07bb8d0e01bdbfb2233f5489f49f1 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:45 +0300 Subject: [PATCH 0279/1451] media: i2c: hi846: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. Now that the runtime PM operations are not called from the system PM handlers, the sensor is guaranteed not to be streaming when the runtime PM resume handler is called, and to have been stopped already when the runtime PM suspend handler is called. Drop the manual stream start/stop from the runtime PM handlers. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/hi846.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/drivers/media/i2c/hi846.c b/drivers/media/i2c/hi846.c index 7fbcc3ff044b7..825fc8dc48f50 100644 --- a/drivers/media/i2c/hi846.c +++ b/drivers/media/i2c/hi846.c @@ -1675,9 +1675,6 @@ static int __maybe_unused hi846_suspend(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); struct hi846 *hi846 = to_hi846(sd); - if (hi846->streaming) - hi846_stop_streaming(hi846); - return hi846_power_off(hi846); } @@ -1686,26 +1683,8 @@ static int __maybe_unused hi846_resume(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct v4l2_subdev *sd = i2c_get_clientdata(client); struct hi846 *hi846 = to_hi846(sd); - int ret; - - ret = hi846_power_on(hi846); - if (ret) - return ret; - - if (hi846->streaming) { - ret = hi846_start_streaming(hi846); - if (ret) { - dev_err(dev, "%s: start streaming failed: %d\n", - __func__, ret); - goto error; - } - } - return 0; - -error: - hi846_power_off(hi846); - return ret; + return hi846_power_on(hi846); } static int hi846_set_format(struct v4l2_subdev *sd, @@ -2168,8 +2147,6 @@ static void hi846_remove(struct i2c_client *client) } static const struct dev_pm_ops hi846_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) SET_RUNTIME_PM_OPS(hi846_suspend, hi846_resume, NULL) }; -- GitLab From 35e663b4a3edf9fa11564abaadb9de8b059cf3b6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:46 +0300 Subject: [PATCH 0280/1451] media: i2c: hi847: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/hi847.c | 52 --------------------------------------- 1 file changed, 52 deletions(-) diff --git a/drivers/media/i2c/hi847.c b/drivers/media/i2c/hi847.c index 47aa2cd06e32d..4075c389804c1 100644 --- a/drivers/media/i2c/hi847.c +++ b/drivers/media/i2c/hi847.c @@ -2184,9 +2184,6 @@ struct hi847 { /* To serialize asynchronus callbacks */ struct mutex mutex; - - /* Streaming on/off */ - bool streaming; }; static u64 to_pixel_rate(u32 f_index) @@ -2618,9 +2615,6 @@ static int hi847_set_stream(struct v4l2_subdev *sd, int enable) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; - if (hi847->streaming == enable) - return 0; - mutex_lock(&hi847->mutex); if (enable) { ret = pm_runtime_resume_and_get(&client->dev); @@ -2640,52 +2634,11 @@ static int hi847_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - hi847->streaming = enable; mutex_unlock(&hi847->mutex); return ret; } -static int __maybe_unused hi847_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct hi847 *hi847 = to_hi847(sd); - - mutex_lock(&hi847->mutex); - if (hi847->streaming) - hi847_stop_streaming(hi847); - - mutex_unlock(&hi847->mutex); - - return 0; -} - -static int __maybe_unused hi847_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct hi847 *hi847 = to_hi847(sd); - int ret; - - mutex_lock(&hi847->mutex); - if (hi847->streaming) { - ret = hi847_start_streaming(hi847); - if (ret) - goto error; - } - - mutex_unlock(&hi847->mutex); - - return 0; - -error: - hi847_stop_streaming(hi847); - hi847->streaming = 0; - mutex_unlock(&hi847->mutex); - return ret; -} - static int hi847_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -2979,10 +2932,6 @@ static int hi847_probe(struct i2c_client *client) return ret; } -static const struct dev_pm_ops hi847_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(hi847_suspend, hi847_resume) -}; - #ifdef CONFIG_ACPI static const struct acpi_device_id hi847_acpi_ids[] = { {"HYV0847"}, @@ -2995,7 +2944,6 @@ MODULE_DEVICE_TABLE(acpi, hi847_acpi_ids); static struct i2c_driver hi847_i2c_driver = { .driver = { .name = "hi847", - .pm = &hi847_pm_ops, .acpi_match_table = ACPI_PTR(hi847_acpi_ids), }, .probe = hi847_probe, -- GitLab From c628b64d313f4c148ec49d1ea75cdb620c5ee7e9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:47 +0300 Subject: [PATCH 0281/1451] media: i2c: imx208: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx208.c | 43 -------------------------------------- 1 file changed, 43 deletions(-) diff --git a/drivers/media/i2c/imx208.c b/drivers/media/i2c/imx208.c index e5c2b47528329..a9b0aea1ae3b8 100644 --- a/drivers/media/i2c/imx208.c +++ b/drivers/media/i2c/imx208.c @@ -290,9 +290,6 @@ struct imx208 { */ struct mutex imx208_mx; - /* Streaming on/off */ - bool streaming; - /* OTP data */ bool otp_read; char otp_data[IMX208_OTP_SIZE]; @@ -734,7 +731,6 @@ static int imx208_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - imx208->streaming = enable; mutex_unlock(&imx208->imx208_mx); /* vflip and hflip cannot change during streaming */ @@ -750,40 +746,6 @@ static int imx208_set_stream(struct v4l2_subdev *sd, int enable) return ret; } -static int __maybe_unused imx208_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct imx208 *imx208 = to_imx208(sd); - - if (imx208->streaming) - imx208_stop_streaming(imx208); - - return 0; -} - -static int __maybe_unused imx208_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct imx208 *imx208 = to_imx208(sd); - int ret; - - if (imx208->streaming) { - ret = imx208_start_streaming(imx208); - if (ret) - goto error; - } - - return 0; - -error: - imx208_stop_streaming(imx208); - imx208->streaming = 0; - - return ret; -} - /* Verify chip ID */ static const struct v4l2_subdev_video_ops imx208_video_ops = { .s_stream = imx208_set_stream, @@ -1077,10 +1039,6 @@ static void imx208_remove(struct i2c_client *client) mutex_destroy(&imx208->imx208_mx); } -static const struct dev_pm_ops imx208_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(imx208_suspend, imx208_resume) -}; - #ifdef CONFIG_ACPI static const struct acpi_device_id imx208_acpi_ids[] = { { "INT3478" }, @@ -1093,7 +1051,6 @@ MODULE_DEVICE_TABLE(acpi, imx208_acpi_ids); static struct i2c_driver imx208_i2c_driver = { .driver = { .name = "imx208", - .pm = &imx208_pm_ops, .acpi_match_table = ACPI_PTR(imx208_acpi_ids), }, .probe = imx208_probe, -- GitLab From 0484cde1dfaacbf8748eb89ea23c274b72466fe3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:48 +0300 Subject: [PATCH 0282/1451] media: i2c: imx214: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Reviewed-by: Ricardo Ribalda Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx214.c | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c index e2805173f4b1a..4f77ea02cc27d 100644 --- a/drivers/media/i2c/imx214.c +++ b/drivers/media/i2c/imx214.c @@ -58,8 +58,6 @@ struct imx214 { * and start streaming. */ struct mutex mutex; - - bool streaming; }; struct reg_8 { @@ -790,7 +788,6 @@ static int imx214_s_stream(struct v4l2_subdev *subdev, int enable) pm_runtime_put(imx214->dev); } - imx214->streaming = enable; return 0; err_rpm_put: @@ -906,39 +903,6 @@ static int imx214_parse_fwnode(struct device *dev) return ret; } -static int __maybe_unused imx214_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct imx214 *imx214 = to_imx214(sd); - - if (imx214->streaming) - imx214_stop_streaming(imx214); - - return 0; -} - -static int __maybe_unused imx214_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct imx214 *imx214 = to_imx214(sd); - int ret; - - if (imx214->streaming) { - ret = imx214_start_streaming(imx214); - if (ret) - goto error; - } - - return 0; - -error: - imx214_stop_streaming(imx214); - imx214->streaming = 0; - return ret; -} - static int imx214_probe(struct i2c_client *client) { struct device *dev = &client->dev; @@ -1099,7 +1063,6 @@ static const struct of_device_id imx214_of_match[] = { MODULE_DEVICE_TABLE(of, imx214_of_match); static const struct dev_pm_ops imx214_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(imx214_suspend, imx214_resume) SET_RUNTIME_PM_OPS(imx214_power_off, imx214_power_on, NULL) }; -- GitLab From b8074db07429b845b805416d261b502f814a80fe Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:49 +0300 Subject: [PATCH 0283/1451] media: i2c: imx219: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 41 -------------------------------------- 1 file changed, 41 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index e247e46db6c04..af29398c657dc 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -479,9 +479,6 @@ struct imx219 { /* Current mode */ const struct imx219_mode *mode; - /* Streaming on/off */ - bool streaming; - /* Two or Four lanes */ u8 lanes; }; @@ -992,8 +989,6 @@ static int imx219_set_stream(struct v4l2_subdev *sd, int enable) imx219_stop_streaming(imx219); } - imx219->streaming = enable; - unlock: v4l2_subdev_unlock_state(state); return ret; @@ -1045,41 +1040,6 @@ static int imx219_power_off(struct device *dev) return 0; } -static int __maybe_unused imx219_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx219 *imx219 = to_imx219(sd); - - if (imx219->streaming) - imx219_stop_streaming(imx219); - - return 0; -} - -static int __maybe_unused imx219_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx219 *imx219 = to_imx219(sd); - struct v4l2_subdev_state *state; - int ret; - - if (imx219->streaming) { - state = v4l2_subdev_lock_and_get_active_state(sd); - ret = imx219_start_streaming(imx219, state); - v4l2_subdev_unlock_state(state); - if (ret) - goto error; - } - - return 0; - -error: - imx219_stop_streaming(imx219); - imx219->streaming = false; - - return ret; -} - static int imx219_get_regulators(struct imx219 *imx219) { struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); @@ -1465,7 +1425,6 @@ static const struct of_device_id imx219_dt_ids[] = { MODULE_DEVICE_TABLE(of, imx219_dt_ids); static const struct dev_pm_ops imx219_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(imx219_suspend, imx219_resume) SET_RUNTIME_PM_OPS(imx219_power_off, imx219_power_on, NULL) }; -- GitLab From e1124ace4504405ee5c81da1bf98f9faf068c44c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:50 +0300 Subject: [PATCH 0284/1451] media: i2c: imx258: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx258.c | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c index 4be0422b7cdac..b3827f4bc0eb3 100644 --- a/drivers/media/i2c/imx258.c +++ b/drivers/media/i2c/imx258.c @@ -622,9 +622,6 @@ struct imx258 { */ struct mutex mutex; - /* Streaming on/off */ - bool streaming; - struct clk *clk; }; @@ -1053,7 +1050,6 @@ static int imx258_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - imx258->streaming = enable; mutex_unlock(&imx258->mutex); return ret; @@ -1066,37 +1062,6 @@ static int imx258_set_stream(struct v4l2_subdev *sd, int enable) return ret; } -static int __maybe_unused imx258_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx258 *imx258 = to_imx258(sd); - - if (imx258->streaming) - imx258_stop_streaming(imx258); - - return 0; -} - -static int __maybe_unused imx258_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx258 *imx258 = to_imx258(sd); - int ret; - - if (imx258->streaming) { - ret = imx258_start_streaming(imx258); - if (ret) - goto error; - } - - return 0; - -error: - imx258_stop_streaming(imx258); - imx258->streaming = 0; - return ret; -} - /* Verify chip ID */ static int imx258_identify_module(struct imx258 *imx258) { @@ -1365,7 +1330,6 @@ static void imx258_remove(struct i2c_client *client) } static const struct dev_pm_ops imx258_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(imx258_suspend, imx258_resume) SET_RUNTIME_PM_OPS(imx258_power_off, imx258_power_on, NULL) }; -- GitLab From 4c9e4ea49abb407bbe33e5b327cd041ef80d72a6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:51 +0300 Subject: [PATCH 0285/1451] media: i2c: imx319: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx319.c | 40 -------------------------------------- 1 file changed, 40 deletions(-) diff --git a/drivers/media/i2c/imx319.c b/drivers/media/i2c/imx319.c index 935bcbacd62e1..5378f607f3401 100644 --- a/drivers/media/i2c/imx319.c +++ b/drivers/media/i2c/imx319.c @@ -138,8 +138,6 @@ struct imx319 { */ struct mutex mutex; - /* Streaming on/off */ - bool streaming; /* True if the device has been identified */ bool identified; }; @@ -2184,8 +2182,6 @@ static int imx319_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - imx319->streaming = enable; - /* vflip and hflip cannot change during streaming */ __v4l2_ctrl_grab(imx319->vflip, enable); __v4l2_ctrl_grab(imx319->hflip, enable); @@ -2202,37 +2198,6 @@ static int imx319_set_stream(struct v4l2_subdev *sd, int enable) return ret; } -static int __maybe_unused imx319_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx319 *imx319 = to_imx319(sd); - - if (imx319->streaming) - imx319_stop_streaming(imx319); - - return 0; -} - -static int __maybe_unused imx319_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx319 *imx319 = to_imx319(sd); - int ret; - - if (imx319->streaming) { - ret = imx319_start_streaming(imx319); - if (ret) - goto error; - } - - return 0; - -error: - imx319_stop_streaming(imx319); - imx319->streaming = 0; - return ret; -} - static const struct v4l2_subdev_core_ops imx319_subdev_core_ops = { .subscribe_event = v4l2_ctrl_subdev_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, @@ -2538,10 +2503,6 @@ static void imx319_remove(struct i2c_client *client) mutex_destroy(&imx319->mutex); } -static const struct dev_pm_ops imx319_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(imx319_suspend, imx319_resume) -}; - static const struct acpi_device_id imx319_acpi_ids[] __maybe_unused = { { "SONY319A" }, { /* sentinel */ } @@ -2551,7 +2512,6 @@ MODULE_DEVICE_TABLE(acpi, imx319_acpi_ids); static struct i2c_driver imx319_i2c_driver = { .driver = { .name = "imx319", - .pm = &imx319_pm_ops, .acpi_match_table = ACPI_PTR(imx319_acpi_ids), }, .probe = imx319_probe, -- GitLab From 96608f4f74c12a7af2afdce11bb7e78fa0a3f085 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:52 +0300 Subject: [PATCH 0286/1451] media: i2c: imx355: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx355.c | 41 -------------------------------------- 1 file changed, 41 deletions(-) diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c index 43c09941704e9..9c58c1a80cba3 100644 --- a/drivers/media/i2c/imx355.c +++ b/drivers/media/i2c/imx355.c @@ -123,9 +123,6 @@ struct imx355 { * Protect access to sensor v4l2 controls. */ struct mutex mutex; - - /* Streaming on/off */ - bool streaming; }; static const struct imx355_reg imx355_global_regs[] = { @@ -1454,8 +1451,6 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - imx355->streaming = enable; - /* vflip and hflip cannot change during streaming */ __v4l2_ctrl_grab(imx355->vflip, enable); __v4l2_ctrl_grab(imx355->hflip, enable); @@ -1472,37 +1467,6 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable) return ret; } -static int __maybe_unused imx355_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx355 *imx355 = to_imx355(sd); - - if (imx355->streaming) - imx355_stop_streaming(imx355); - - return 0; -} - -static int __maybe_unused imx355_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx355 *imx355 = to_imx355(sd); - int ret; - - if (imx355->streaming) { - ret = imx355_start_streaming(imx355); - if (ret) - goto error; - } - - return 0; - -error: - imx355_stop_streaming(imx355); - imx355->streaming = 0; - return ret; -} - /* Verify chip ID */ static int imx355_identify_module(struct imx355 *imx355) { @@ -1825,10 +1789,6 @@ static void imx355_remove(struct i2c_client *client) mutex_destroy(&imx355->mutex); } -static const struct dev_pm_ops imx355_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(imx355_suspend, imx355_resume) -}; - static const struct acpi_device_id imx355_acpi_ids[] __maybe_unused = { { "SONY355A" }, { /* sentinel */ } @@ -1838,7 +1798,6 @@ MODULE_DEVICE_TABLE(acpi, imx355_acpi_ids); static struct i2c_driver imx355_i2c_driver = { .driver = { .name = "imx355", - .pm = &imx355_pm_ops, .acpi_match_table = ACPI_PTR(imx355_acpi_ids), }, .probe = imx355_probe, -- GitLab From b477adeb9a4645413131f764a35abb58ccd097b6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:53 +0300 Subject: [PATCH 0287/1451] media: i2c: og01a1b: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/og01a1b.c | 47 ------------------------------------- 1 file changed, 47 deletions(-) diff --git a/drivers/media/i2c/og01a1b.c b/drivers/media/i2c/og01a1b.c index 956ad3e996b64..51378ba16a5d4 100644 --- a/drivers/media/i2c/og01a1b.c +++ b/drivers/media/i2c/og01a1b.c @@ -434,9 +434,6 @@ struct og01a1b { /* To serialize asynchronus callbacks */ struct mutex mutex; - - /* Streaming on/off */ - bool streaming; }; static u64 to_pixel_rate(u32 f_index) @@ -751,50 +748,11 @@ static int og01a1b_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - og01a1b->streaming = enable; mutex_unlock(&og01a1b->mutex); return ret; } -static int __maybe_unused og01a1b_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct og01a1b *og01a1b = to_og01a1b(sd); - - mutex_lock(&og01a1b->mutex); - if (og01a1b->streaming) - og01a1b_stop_streaming(og01a1b); - - mutex_unlock(&og01a1b->mutex); - - return 0; -} - -static int __maybe_unused og01a1b_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct og01a1b *og01a1b = to_og01a1b(sd); - int ret; - - mutex_lock(&og01a1b->mutex); - if (og01a1b->streaming) { - ret = og01a1b_start_streaming(og01a1b); - if (ret) { - og01a1b->streaming = false; - og01a1b_stop_streaming(og01a1b); - mutex_unlock(&og01a1b->mutex); - return ret; - } - } - - mutex_unlock(&og01a1b->mutex); - - return 0; -} - static int og01a1b_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -1092,10 +1050,6 @@ static int og01a1b_probe(struct i2c_client *client) return ret; } -static const struct dev_pm_ops og01a1b_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(og01a1b_suspend, og01a1b_resume) -}; - #ifdef CONFIG_ACPI static const struct acpi_device_id og01a1b_acpi_ids[] = { {"OVTI01AC"}, @@ -1108,7 +1062,6 @@ MODULE_DEVICE_TABLE(acpi, og01a1b_acpi_ids); static struct i2c_driver og01a1b_i2c_driver = { .driver = { .name = "og01a1b", - .pm = &og01a1b_pm_ops, .acpi_match_table = ACPI_PTR(og01a1b_acpi_ids), }, .probe = og01a1b_probe, -- GitLab From 6f40f7caf7b66e32392ba6a46136d3faf5dff9be Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:54 +0300 Subject: [PATCH 0288/1451] media: i2c: ov01a10: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov01a10.c | 57 ++----------------------------------- 1 file changed, 3 insertions(+), 54 deletions(-) diff --git a/drivers/media/i2c/ov01a10.c b/drivers/media/i2c/ov01a10.c index b43c1c96f47bc..bbd5740d2280b 100644 --- a/drivers/media/i2c/ov01a10.c +++ b/drivers/media/i2c/ov01a10.c @@ -287,9 +287,6 @@ struct ov01a10 { struct v4l2_ctrl *exposure; const struct ov01a10_mode *cur_mode; - - /* streaming state */ - bool streaming; }; static inline struct ov01a10 *to_ov01a10(struct v4l2_subdev *subdev) @@ -683,55 +680,12 @@ static int ov01a10_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); goto unlock; } - - goto done; - } - - ov01a10_stop_streaming(ov01a10); - pm_runtime_put(&client->dev); -done: - ov01a10->streaming = enable; -unlock: - v4l2_subdev_unlock_state(state); - - return ret; -} - -static int __maybe_unused ov01a10_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov01a10 *ov01a10 = to_ov01a10(sd); - struct v4l2_subdev_state *state; - - state = v4l2_subdev_lock_and_get_active_state(sd); - if (ov01a10->streaming) - ov01a10_stop_streaming(ov01a10); - - v4l2_subdev_unlock_state(state); - - return 0; -} - -static int __maybe_unused ov01a10_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov01a10 *ov01a10 = to_ov01a10(sd); - struct v4l2_subdev_state *state; - int ret = 0; - - state = v4l2_subdev_lock_and_get_active_state(sd); - if (!ov01a10->streaming) - goto exit; - - ret = ov01a10_start_streaming(ov01a10); - if (ret) { - ov01a10->streaming = false; + } else { ov01a10_stop_streaming(ov01a10); + pm_runtime_put(&client->dev); } -exit: +unlock: v4l2_subdev_unlock_state(state); return ret; @@ -971,10 +925,6 @@ static int ov01a10_probe(struct i2c_client *client) return ret; } -static const struct dev_pm_ops ov01a10_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ov01a10_suspend, ov01a10_resume) -}; - #ifdef CONFIG_ACPI static const struct acpi_device_id ov01a10_acpi_ids[] = { { "OVTI01A0" }, @@ -987,7 +937,6 @@ MODULE_DEVICE_TABLE(acpi, ov01a10_acpi_ids); static struct i2c_driver ov01a10_i2c_driver = { .driver = { .name = "ov01a10", - .pm = &ov01a10_pm_ops, .acpi_match_table = ACPI_PTR(ov01a10_acpi_ids), }, .probe = ov01a10_probe, -- GitLab From 480ff48163e5b24ba39681fb50bb486cf95a019f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:55 +0300 Subject: [PATCH 0289/1451] media: i2c: ov02a10: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov02a10.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/i2c/ov02a10.c b/drivers/media/i2c/ov02a10.c index 741d977a76f32..848e47a464acf 100644 --- a/drivers/media/i2c/ov02a10.c +++ b/drivers/media/i2c/ov02a10.c @@ -570,8 +570,6 @@ static int ov02a10_s_stream(struct v4l2_subdev *sd, int on) } static const struct dev_pm_ops ov02a10_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) SET_RUNTIME_PM_OPS(ov02a10_power_off, ov02a10_power_on, NULL) }; -- GitLab From a1c4cca2167babf1c267b6640b524278170fd9e6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:56 +0300 Subject: [PATCH 0290/1451] media: i2c: ov08d10: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov08d10.c | 49 ------------------------------------- 1 file changed, 49 deletions(-) diff --git a/drivers/media/i2c/ov08d10.c b/drivers/media/i2c/ov08d10.c index ef811711549cf..3d49e3fa8e562 100644 --- a/drivers/media/i2c/ov08d10.c +++ b/drivers/media/i2c/ov08d10.c @@ -536,9 +536,6 @@ struct ov08d10 { /* To serialize asynchronus callbacks */ struct mutex mutex; - /* Streaming on/off */ - bool streaming; - /* lanes index */ u8 nlanes; @@ -1122,8 +1119,6 @@ static int ov08d10_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - ov08d10->streaming = enable; - /* vflip and hflip cannot change during streaming */ __v4l2_ctrl_grab(ov08d10->vflip, enable); __v4l2_ctrl_grab(ov08d10->hflip, enable); @@ -1133,45 +1128,6 @@ static int ov08d10_set_stream(struct v4l2_subdev *sd, int enable) return ret; } -static int __maybe_unused ov08d10_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov08d10 *ov08d10 = to_ov08d10(sd); - - mutex_lock(&ov08d10->mutex); - if (ov08d10->streaming) - ov08d10_stop_streaming(ov08d10); - - mutex_unlock(&ov08d10->mutex); - - return 0; -} - -static int __maybe_unused ov08d10_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov08d10 *ov08d10 = to_ov08d10(sd); - int ret; - - mutex_lock(&ov08d10->mutex); - - if (ov08d10->streaming) { - ret = ov08d10_start_streaming(ov08d10); - if (ret) { - ov08d10->streaming = false; - ov08d10_stop_streaming(ov08d10); - mutex_unlock(&ov08d10->mutex); - return ret; - } - } - - mutex_unlock(&ov08d10->mutex); - - return 0; -} - static int ov08d10_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -1498,10 +1454,6 @@ static int ov08d10_probe(struct i2c_client *client) return ret; } -static const struct dev_pm_ops ov08d10_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ov08d10_suspend, ov08d10_resume) -}; - #ifdef CONFIG_ACPI static const struct acpi_device_id ov08d10_acpi_ids[] = { { "OVTI08D1" }, @@ -1514,7 +1466,6 @@ MODULE_DEVICE_TABLE(acpi, ov08d10_acpi_ids); static struct i2c_driver ov08d10_i2c_driver = { .driver = { .name = "ov08d10", - .pm = &ov08d10_pm_ops, .acpi_match_table = ACPI_PTR(ov08d10_acpi_ids), }, .probe = ov08d10_probe, -- GitLab From b8b84d75304404c7c5a63d863e0000d748892628 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:57 +0300 Subject: [PATCH 0291/1451] media: i2c: ov08x40: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov08x40.c | 40 ------------------------------------- 1 file changed, 40 deletions(-) diff --git a/drivers/media/i2c/ov08x40.c b/drivers/media/i2c/ov08x40.c index 1ea402550837b..b41b6866a0ab2 100644 --- a/drivers/media/i2c/ov08x40.c +++ b/drivers/media/i2c/ov08x40.c @@ -2432,9 +2432,6 @@ struct ov08x40 { /* Mutex for serialized access */ struct mutex mutex; - - /* Streaming on/off */ - bool streaming; }; #define to_ov08x40(_sd) container_of(_sd, struct ov08x40, sd) @@ -2933,7 +2930,6 @@ static int ov08x40_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - ov08x->streaming = enable; mutex_unlock(&ov08x->mutex); return ret; @@ -2946,37 +2942,6 @@ static int ov08x40_set_stream(struct v4l2_subdev *sd, int enable) return ret; } -static int __maybe_unused ov08x40_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov08x40 *ov08x = to_ov08x40(sd); - - if (ov08x->streaming) - ov08x40_stop_streaming(ov08x); - - return 0; -} - -static int __maybe_unused ov08x40_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov08x40 *ov08x = to_ov08x40(sd); - int ret; - - if (ov08x->streaming) { - ret = ov08x40_start_streaming(ov08x); - if (ret) - goto error; - } - - return 0; - -error: - ov08x40_stop_streaming(ov08x); - ov08x->streaming = false; - return ret; -} - /* Verify chip ID */ static int ov08x40_identify_module(struct ov08x40 *ov08x) { @@ -3290,10 +3255,6 @@ static void ov08x40_remove(struct i2c_client *client) pm_runtime_set_suspended(&client->dev); } -static const struct dev_pm_ops ov08x40_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ov08x40_suspend, ov08x40_resume) -}; - #ifdef CONFIG_ACPI static const struct acpi_device_id ov08x40_acpi_ids[] = { {"OVTI08F4"}, @@ -3306,7 +3267,6 @@ MODULE_DEVICE_TABLE(acpi, ov08x40_acpi_ids); static struct i2c_driver ov08x40_i2c_driver = { .driver = { .name = "ov08x40", - .pm = &ov08x40_pm_ops, .acpi_match_table = ACPI_PTR(ov08x40_acpi_ids), }, .probe = ov08x40_probe, -- GitLab From f82344daa782d6621a2b7f4ca30358386e7c3247 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:58 +0300 Subject: [PATCH 0292/1451] media: i2c: ov13858: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov13858.c | 40 ------------------------------------- 1 file changed, 40 deletions(-) diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index b90ce338a47a9..4c419014dd7b2 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -1044,9 +1044,6 @@ struct ov13858 { /* Mutex for serialized access */ struct mutex mutex; - - /* Streaming on/off */ - bool streaming; }; #define to_ov13858(_sd) container_of(_sd, struct ov13858, sd) @@ -1485,7 +1482,6 @@ static int ov13858_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - ov13858->streaming = enable; mutex_unlock(&ov13858->mutex); return ret; @@ -1498,37 +1494,6 @@ static int ov13858_set_stream(struct v4l2_subdev *sd, int enable) return ret; } -static int __maybe_unused ov13858_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov13858 *ov13858 = to_ov13858(sd); - - if (ov13858->streaming) - ov13858_stop_streaming(ov13858); - - return 0; -} - -static int __maybe_unused ov13858_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov13858 *ov13858 = to_ov13858(sd); - int ret; - - if (ov13858->streaming) { - ret = ov13858_start_streaming(ov13858); - if (ret) - goto error; - } - - return 0; - -error: - ov13858_stop_streaming(ov13858); - ov13858->streaming = false; - return ret; -} - /* Verify chip ID */ static int ov13858_identify_module(struct ov13858 *ov13858) { @@ -1783,10 +1748,6 @@ static const struct i2c_device_id ov13858_id_table[] = { MODULE_DEVICE_TABLE(i2c, ov13858_id_table); -static const struct dev_pm_ops ov13858_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ov13858_suspend, ov13858_resume) -}; - #ifdef CONFIG_ACPI static const struct acpi_device_id ov13858_acpi_ids[] = { {"OVTID858"}, @@ -1799,7 +1760,6 @@ MODULE_DEVICE_TABLE(acpi, ov13858_acpi_ids); static struct i2c_driver ov13858_i2c_driver = { .driver = { .name = "ov13858", - .pm = &ov13858_pm_ops, .acpi_match_table = ACPI_PTR(ov13858_acpi_ids), }, .probe = ov13858_probe, -- GitLab From 55e941d06a761be4f769c1c2e1fff3664c78ab4a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:16:59 +0300 Subject: [PATCH 0293/1451] media: i2c: ov2740: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov2740.c | 42 -------------------------------------- 1 file changed, 42 deletions(-) diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index 59356dd9afd81..3a9700fbbe8cb 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -339,9 +339,6 @@ struct ov2740 { /* To serialize asynchronus callbacks */ struct mutex mutex; - /* Streaming on/off */ - bool streaming; - /* NVM data inforamtion */ struct nvm_data *nvm; @@ -813,47 +810,11 @@ static int ov2740_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - ov2740->streaming = enable; mutex_unlock(&ov2740->mutex); return ret; } -static int ov2740_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov2740 *ov2740 = to_ov2740(sd); - - mutex_lock(&ov2740->mutex); - if (ov2740->streaming) - ov2740_stop_streaming(ov2740); - - mutex_unlock(&ov2740->mutex); - - return 0; -} - -static int ov2740_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov2740 *ov2740 = to_ov2740(sd); - int ret = 0; - - mutex_lock(&ov2740->mutex); - if (!ov2740->streaming) - goto exit; - - ret = ov2740_start_streaming(ov2740); - if (ret) { - ov2740->streaming = false; - ov2740_stop_streaming(ov2740); - } - -exit: - mutex_unlock(&ov2740->mutex); - return ret; -} - static int ov2740_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -1197,8 +1158,6 @@ static int ov2740_probe(struct i2c_client *client) return ret; } -static DEFINE_SIMPLE_DEV_PM_OPS(ov2740_pm_ops, ov2740_suspend, ov2740_resume); - static const struct acpi_device_id ov2740_acpi_ids[] = { {"INT3474"}, {} @@ -1209,7 +1168,6 @@ MODULE_DEVICE_TABLE(acpi, ov2740_acpi_ids); static struct i2c_driver ov2740_i2c_driver = { .driver = { .name = "ov2740", - .pm = pm_sleep_ptr(&ov2740_pm_ops), .acpi_match_table = ov2740_acpi_ids, }, .probe = ov2740_probe, -- GitLab From 5c873f079da7751957f3cfa02da38a8d15ffde65 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:17:00 +0300 Subject: [PATCH 0294/1451] media: i2c: ov13b10: Drop stream handling in runtime PM handlers The sensor is guaranteed not to be streaming when the runtime PM resume handler is called, as the resume handler is only called from the .s_stream() operation when starting streaming. Similarly, the sensor has been stopped when the runtime PM suspend handler is called. There is thus no need for manual stream start/stop from the runtime PM handlers. Drop them. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov13b10.c | 34 +--------------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/drivers/media/i2c/ov13b10.c b/drivers/media/i2c/ov13b10.c index 32c598ed77522..970d2caeb3d62 100644 --- a/drivers/media/i2c/ov13b10.c +++ b/drivers/media/i2c/ov13b10.c @@ -650,9 +650,6 @@ struct ov13b10 { /* Mutex for serialized access */ struct mutex mutex; - /* Streaming on/off */ - bool streaming; - /* True if the device has been identified */ bool identified; }; @@ -1235,7 +1232,6 @@ static int ov13b10_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - ov13b->streaming = enable; mutex_unlock(&ov13b->mutex); return ret; @@ -1250,12 +1246,6 @@ static int ov13b10_set_stream(struct v4l2_subdev *sd, int enable) static int ov13b10_suspend(struct device *dev) { - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov13b10 *ov13b = to_ov13b10(sd); - - if (ov13b->streaming) - ov13b10_stop_streaming(ov13b); - ov13b10_power_off(dev); return 0; @@ -1263,29 +1253,7 @@ static int ov13b10_suspend(struct device *dev) static int ov13b10_resume(struct device *dev) { - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov13b10 *ov13b = to_ov13b10(sd); - int ret; - - ret = ov13b10_power_on(dev); - if (ret) - goto pm_fail; - - if (ov13b->streaming) { - ret = ov13b10_start_streaming(ov13b); - if (ret) - goto stop_streaming; - } - - return 0; - -stop_streaming: - ov13b10_stop_streaming(ov13b); - ov13b10_power_off(dev); -pm_fail: - ov13b->streaming = false; - - return ret; + return ov13b10_power_on(dev); } static const struct v4l2_subdev_video_ops ov13b10_video_ops = { -- GitLab From b268547c5c094df94186c8cad26904a4ffa5ae1c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:17:01 +0300 Subject: [PATCH 0295/1451] media: i2c: ov5670: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov5670.c | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index afd84c8e5ee79..e80db3ecd4f80 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -1882,8 +1882,6 @@ struct ov5670 { /* To serialize asynchronus callbacks */ struct mutex mutex; - /* Streaming on/off */ - bool streaming; /* True if the device has been identified */ bool identified; }; @@ -2484,7 +2482,6 @@ static int ov5670_set_stream(struct v4l2_subdev *sd, int enable) ret = ov5670_stop_streaming(ov5670); pm_runtime_put(&client->dev); } - ov5670->streaming = enable; goto unlock_and_return; error: @@ -2539,34 +2536,6 @@ static int __maybe_unused ov5670_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused ov5670_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov5670 *ov5670 = to_ov5670(sd); - - if (ov5670->streaming) - ov5670_stop_streaming(ov5670); - - return 0; -} - -static int __maybe_unused ov5670_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov5670 *ov5670 = to_ov5670(sd); - int ret; - - if (ov5670->streaming) { - ret = ov5670_start_streaming(ov5670); - if (ret) { - ov5670_stop_streaming(ov5670); - return ret; - } - } - - return 0; -} - static const struct v4l2_subdev_core_ops ov5670_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, .subscribe_event = v4l2_ctrl_subdev_subscribe_event, @@ -2769,8 +2738,6 @@ static int ov5670_probe(struct i2c_client *client) goto error_handler_free; } - ov5670->streaming = false; - /* Set the device's state to active if it's in D0 state. */ if (full_power) pm_runtime_set_active(&client->dev); @@ -2825,7 +2792,6 @@ static void ov5670_remove(struct i2c_client *client) } static const struct dev_pm_ops ov5670_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ov5670_suspend, ov5670_resume) SET_RUNTIME_PM_OPS(ov5670_runtime_suspend, ov5670_runtime_resume, NULL) }; -- GitLab From 046da914bf5ff9c8c89f708b63c488e3e88610b6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:17:02 +0300 Subject: [PATCH 0296/1451] media: i2c: ov5675: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov5675.c | 41 -------------------------------------- 1 file changed, 41 deletions(-) diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c index f608ee0c0cec4..e63d9d402d340 100644 --- a/drivers/media/i2c/ov5675.c +++ b/drivers/media/i2c/ov5675.c @@ -513,9 +513,6 @@ struct ov5675 { /* To serialize asynchronus callbacks */ struct mutex mutex; - /* Streaming on/off */ - bool streaming; - /* True if the device has been identified */ bool identified; }; @@ -968,7 +965,6 @@ static int ov5675_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - ov5675->streaming = enable; mutex_unlock(&ov5675->mutex); return ret; @@ -1024,42 +1020,6 @@ static int ov5675_power_on(struct device *dev) return 0; } -static int __maybe_unused ov5675_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov5675 *ov5675 = to_ov5675(sd); - - mutex_lock(&ov5675->mutex); - if (ov5675->streaming) - ov5675_stop_streaming(ov5675); - - mutex_unlock(&ov5675->mutex); - - return 0; -} - -static int __maybe_unused ov5675_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov5675 *ov5675 = to_ov5675(sd); - int ret; - - mutex_lock(&ov5675->mutex); - if (ov5675->streaming) { - ret = ov5675_start_streaming(ov5675); - if (ret) { - ov5675->streaming = false; - ov5675_stop_streaming(ov5675); - mutex_unlock(&ov5675->mutex); - return ret; - } - } - - mutex_unlock(&ov5675->mutex); - - return 0; -} - static int ov5675_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -1406,7 +1366,6 @@ static int ov5675_probe(struct i2c_client *client) } static const struct dev_pm_ops ov5675_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ov5675_suspend, ov5675_resume) SET_RUNTIME_PM_OPS(ov5675_power_off, ov5675_power_on, NULL) }; -- GitLab From 19ae6ba57f88dc4d01cd2a5dc6c4ca367ead8552 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:17:03 +0300 Subject: [PATCH 0297/1451] media: i2c: ov8856: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov8856.c | 44 -------------------------------------- 1 file changed, 44 deletions(-) diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index 5447a33619762..a0f673a24e529 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -1438,9 +1438,6 @@ struct ov8856 { /* To serialize asynchronus callbacks */ struct mutex mutex; - /* Streaming on/off */ - bool streaming; - /* lanes index */ u8 nlanes; @@ -2061,7 +2058,6 @@ static int ov8856_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - ov8856->streaming = enable; mutex_unlock(&ov8856->mutex); return ret; @@ -2122,45 +2118,6 @@ static int ov8856_power_off(struct device *dev) return 0; } -static int __maybe_unused ov8856_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov8856 *ov8856 = to_ov8856(sd); - - mutex_lock(&ov8856->mutex); - if (ov8856->streaming) - ov8856_stop_streaming(ov8856); - - ov8856_power_off(dev); - mutex_unlock(&ov8856->mutex); - - return 0; -} - -static int __maybe_unused ov8856_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov8856 *ov8856 = to_ov8856(sd); - int ret; - - mutex_lock(&ov8856->mutex); - - ov8856_power_on(dev); - if (ov8856->streaming) { - ret = ov8856_start_streaming(ov8856); - if (ret) { - ov8856->streaming = false; - ov8856_stop_streaming(ov8856); - mutex_unlock(&ov8856->mutex); - return ret; - } - } - - mutex_unlock(&ov8856->mutex); - - return 0; -} - static int ov8856_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -2498,7 +2455,6 @@ static int ov8856_probe(struct i2c_client *client) } static const struct dev_pm_ops ov8856_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ov8856_suspend, ov8856_resume) SET_RUNTIME_PM_OPS(ov8856_power_off, ov8856_power_on, NULL) }; -- GitLab From 56e9e480b6f2b8790798a89a5a8419683164cb17 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 14 Sep 2023 21:17:04 +0300 Subject: [PATCH 0298/1451] media: i2c: ov9734: Drop system suspend and resume handlers Stopping streaming on a camera pipeline at system suspend time, and restarting it at system resume time, requires coordinated action between the bridge driver and the camera sensor driver. This is handled by the bridge driver calling the sensor's .s_stream() handler at system suspend and resume time. There is thus no need for the sensor to independently implement system sleep PM operations. Drop them. The streaming field of the driver's private structure is now unused, drop it as well. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov9734.c | 46 -------------------------------------- 1 file changed, 46 deletions(-) diff --git a/drivers/media/i2c/ov9734.c b/drivers/media/i2c/ov9734.c index a5f91499bce49..ee33152996055 100644 --- a/drivers/media/i2c/ov9734.c +++ b/drivers/media/i2c/ov9734.c @@ -337,9 +337,6 @@ struct ov9734 { /* To serialize asynchronus callbacks */ struct mutex mutex; - - /* Streaming on/off */ - bool streaming; }; static inline struct ov9734 *to_ov9734(struct v4l2_subdev *subdev) @@ -679,49 +676,11 @@ static int ov9734_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - ov9734->streaming = enable; mutex_unlock(&ov9734->mutex); return ret; } -static int __maybe_unused ov9734_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov9734 *ov9734 = to_ov9734(sd); - - mutex_lock(&ov9734->mutex); - if (ov9734->streaming) - ov9734_stop_streaming(ov9734); - - mutex_unlock(&ov9734->mutex); - - return 0; -} - -static int __maybe_unused ov9734_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov9734 *ov9734 = to_ov9734(sd); - int ret = 0; - - mutex_lock(&ov9734->mutex); - if (!ov9734->streaming) - goto exit; - - ret = ov9734_start_streaming(ov9734); - if (ret) { - ov9734->streaming = false; - ov9734_stop_streaming(ov9734); - } - -exit: - mutex_unlock(&ov9734->mutex); - return ret; -} - static int ov9734_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -1007,10 +966,6 @@ static int ov9734_probe(struct i2c_client *client) return ret; } -static const struct dev_pm_ops ov9734_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ov9734_suspend, ov9734_resume) -}; - static const struct acpi_device_id ov9734_acpi_ids[] = { { "OVTI9734", }, {} @@ -1021,7 +976,6 @@ MODULE_DEVICE_TABLE(acpi, ov9734_acpi_ids); static struct i2c_driver ov9734_i2c_driver = { .driver = { .name = "ov9734", - .pm = &ov9734_pm_ops, .acpi_match_table = ov9734_acpi_ids, }, .probe = ov9734_probe, -- GitLab From bd5b50b329e850d467e7bcc07b2b6bde3752fbda Mon Sep 17 00:00:00 2001 From: Zheng Wang Date: Thu, 13 Apr 2023 11:49:42 +0800 Subject: [PATCH 0299/1451] media: bttv: fix use after free error due to btv->timeout timer There may be some a race condition between timer function bttv_irq_timeout and bttv_remove. The timer is setup in probe and there is no timer_delete operation in remove function. When it hit kfree btv, the function might still be invoked, which will cause use after free bug. This bug is found by static analysis, it may be false positive. Fix it by adding del_timer_sync invoking to the remove function. cpu0 cpu1 bttv_probe ->timer_setup ->bttv_set_dma ->mod_timer; bttv_remove ->kfree(btv); ->bttv_irq_timeout ->USE btv Fixes: 162e6376ac58 ("media: pci: Convert timers to use timer_setup()") Signed-off-by: Zheng Wang Signed-off-by: Hans Verkuil --- drivers/media/pci/bt8xx/bttv-driver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index aa708a0e5eac6..09a193bb87df3 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -3474,6 +3474,7 @@ static void bttv_remove(struct pci_dev *pci_dev) /* free resources */ free_irq(btv->c.pci->irq,btv); + del_timer_sync(&btv->timeout); iounmap(btv->bt848_mmio); release_mem_region(pci_resource_start(btv->c.pci,0), pci_resource_len(btv->c.pci,0)); -- GitLab From 1a6c4bada40a02cadf0ca7c6deab78c163774566 Mon Sep 17 00:00:00 2001 From: Juerg Haefliger Date: Fri, 16 Jun 2023 14:04:06 +0200 Subject: [PATCH 0300/1451] media: bttv: Add MODULE_FIRMWARE macro The module loads firmware so add a MODULE_FIRMWARE macro to provide that information via modinfo. Signed-off-by: Juerg Haefliger Signed-off-by: Hans Verkuil --- drivers/media/pci/bt8xx/bttv-cards.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c index ec78f7fc5e1b6..867c1308de235 100644 --- a/drivers/media/pci/bt8xx/bttv-cards.c +++ b/drivers/media/pci/bt8xx/bttv-cards.c @@ -126,6 +126,7 @@ MODULE_PARM_DESC(audiodev, "specify audio device:\n" "\t\t 3 = tvaudio"); MODULE_PARM_DESC(saa6588, "if 1, then load the saa6588 RDS module, default (0) is to use the card definition."); +MODULE_FIRMWARE("hcwamc.rbf"); /* I2C addresses list */ #define I2C_ADDR_TDA7432 0x8a -- GitLab From 026c341795e593df640b901f8d36f90a2461a180 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 27 Jun 2023 16:37:38 +0100 Subject: [PATCH 0301/1451] media: bt8xx: make read-only arrays static Don't populate the arrays on the stack, instead make them static const. Also add spaces between values to clean up checkpatch style warnings. Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil --- drivers/media/pci/bt8xx/dvb-bt8xx.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/media/pci/bt8xx/dvb-bt8xx.c b/drivers/media/pci/bt8xx/dvb-bt8xx.c index 4cb890b949c3d..390cbba6c065a 100644 --- a/drivers/media/pci/bt8xx/dvb-bt8xx.c +++ b/drivers/media/pci/bt8xx/dvb-bt8xx.c @@ -190,11 +190,15 @@ static int cx24108_tuner_set_params(struct dvb_frontend *fe) u32 freq = c->frequency; int i, a, n, pump; u32 band, pll; - u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000, - 1576000,1718000,1856000,2036000,2150000}; - u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000, - 0x00102000,0x00104000,0x00108000,0x00110000, - 0x00120000,0x00140000}; + static const u32 osci[] = { + 950000, 1019000, 1075000, 1178000, 1296000, 1432000, + 1576000, 1718000, 1856000, 2036000, 2150000 + }; + static const u32 bandsel[] = { + 0, 0x00020000, 0x00040000, 0x00100800, 0x00101000, + 0x00102000, 0x00104000, 0x00108000, 0x00110000, + 0x00120000, 0x00140000 + }; #define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */ dprintk("cx24108 debug: entering SetTunerFreq, freq=%d\n", freq); -- GitLab From 3f1e1f69ad6c13c9e9fadd0595f7e2ce33ba89a1 Mon Sep 17 00:00:00 2001 From: Wang Ming Date: Wed, 26 Jul 2023 19:51:58 +0800 Subject: [PATCH 0302/1451] media: platform: Use dev_err_probe instead of dev_err It is possible that dma_request_chan will return EPROBE_DEFER, which means that dma->xdev->dev is not ready yet. In this case, dev_err(dma->xdev->dev), there will be no output. This patch fixes the bug. Signed-off-by: Wang Ming Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/xilinx/xilinx-dma.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index 80d6f5b072ea6..a96de5d388a1d 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -708,9 +708,8 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma, snprintf(name, sizeof(name), "port%u", port); dma->dma = dma_request_chan(dma->xdev->dev, name); if (IS_ERR(dma->dma)) { - ret = PTR_ERR(dma->dma); - if (ret != -EPROBE_DEFER) - dev_err(dma->xdev->dev, "no VDMA channel found\n"); + ret = dev_err_probe(dma->xdev->dev, PTR_ERR(dma->dma), + "no VDMA channel found\n"); goto error; } -- GitLab From 57a3afc5d542afcb4ca0ddd3379ab95c984bba88 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 3 Aug 2023 09:42:10 +0200 Subject: [PATCH 0303/1451] media: cx25840: simplify cx23885_dif_setup() Instead of creating a huge switch statement (that thoroughly confuses smatch), create a table of coefficients and use that. Signed-off-by: Hans Verkuil --- drivers/media/i2c/cx25840/cx25840-core.c | 3694 +++++----------------- 1 file changed, 811 insertions(+), 2883 deletions(-) diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 5aec252890624..04461c893d906 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -2738,10 +2738,801 @@ static int cx25840_irq_handler(struct v4l2_subdev *sd, u32 status, #define DIF_BPF_COEFF3435 (0x38c) #define DIF_BPF_COEFF36 (0x390) +static const u32 ifhz_coeffs[][19] = { + { // 3.0 MHz + 0x00000002, 0x00080012, 0x001e0024, 0x001bfff8, + 0xffb4ff50, 0xfed8fe68, 0xfe24fe34, 0xfebaffc7, + 0x014d031f, 0x04f0065d, 0x07010688, 0x04c901d6, + 0xfe00f9d3, 0xf600f342, 0xf235f337, 0xf64efb22, + 0x0105070f, 0x0c460fce, 0x110d0000, + }, { // 3.1 MHz + 0x00000001, 0x00070012, 0x00220032, 0x00370026, + 0xfff0ff91, 0xff0efe7c, 0xfe01fdcc, 0xfe0afedb, + 0x00440224, 0x0434060c, 0x0738074e, 0x06090361, + 0xff99fb39, 0xf6fef3b6, 0xf21af2a5, 0xf573fa33, + 0x0034067d, 0x0bfb0fb9, 0x110d0000, + }, { // 3.2 MHz + 0x00000000, 0x0004000e, 0x00200038, 0x004c004f, + 0x002fffdf, 0xff5cfeb6, 0xfe0dfd92, 0xfd7ffe03, + 0xff36010a, 0x03410575, 0x072607d2, 0x071804d5, + 0x0134fcb7, 0xf81ff451, 0xf223f22e, 0xf4a7f94b, + 0xff6405e8, 0x0bae0fa4, 0x110d0000, + }, { // 3.3 MHz + 0x0000ffff, 0x00000008, 0x001a0036, 0x0056006d, + 0x00670030, 0xffbdff10, 0xfe46fd8d, 0xfd25fd4f, + 0xfe35ffe0, 0x0224049f, 0x06c9080e, 0x07ef0627, + 0x02c9fe45, 0xf961f513, 0xf250f1d2, 0xf3ecf869, + 0xfe930552, 0x0b5f0f8f, 0x110d0000, + }, { // 3.4 MHz + 0xfffffffe, 0xfffd0001, 0x000f002c, 0x0054007d, + 0x0093007c, 0x0024ff82, 0xfea6fdbb, 0xfd03fcca, + 0xfd51feb9, 0x00eb0392, 0x06270802, 0x08880750, + 0x044dffdb, 0xfabdf5f8, 0xf2a0f193, 0xf342f78f, + 0xfdc404b9, 0x0b0e0f78, 0x110d0000, + }, { // 3.5 MHz + 0xfffffffd, 0xfffafff9, 0x0002001b, 0x0046007d, + 0x00ad00ba, 0x00870000, 0xff26fe1a, 0xfd1bfc7e, + 0xfc99fda4, 0xffa5025c, 0x054507ad, 0x08dd0847, + 0x05b80172, 0xfc2ef6ff, 0xf313f170, 0xf2abf6bd, + 0xfcf6041f, 0x0abc0f61, 0x110d0000, + }, { // 3.6 MHz + 0xfffffffd, 0xfff8fff3, 0xfff50006, 0x002f006c, + 0x00b200e3, 0x00dc007e, 0xffb9fea0, 0xfd6bfc71, + 0xfc17fcb1, 0xfe65010b, 0x042d0713, 0x08ec0906, + 0x07020302, 0xfdaff823, 0xf3a7f16a, 0xf228f5f5, + 0xfc2a0384, 0x0a670f4a, 0x110d0000, + }, { // 3.7 MHz + 0x0000fffd, 0xfff7ffef, 0xffe9fff1, 0x0010004d, + 0x00a100f2, 0x011a00f0, 0x0053ff44, 0xfdedfca2, + 0xfbd3fbef, 0xfd39ffae, 0x02ea0638, 0x08b50987, + 0x08230483, 0xff39f960, 0xf45bf180, 0xf1b8f537, + 0xfb6102e7, 0x0a110f32, 0x110d0000, + }, { // 3.8 MHz + 0x0000fffe, 0xfff9ffee, 0xffe1ffdd, 0xfff00024, + 0x007c00e5, 0x013a014a, 0x00e6fff8, 0xfe98fd0f, + 0xfbd3fb67, 0xfc32fe54, 0x01880525, 0x083909c7, + 0x091505ee, 0x00c7fab3, 0xf52df1b4, 0xf15df484, + 0xfa9b0249, 0x09ba0f19, 0x110d0000, + }, { // 3.9 MHz + 0x00000000, 0xfffbfff0, 0xffdeffcf, 0xffd1fff6, + 0x004800be, 0x01390184, 0x016300ac, 0xff5efdb1, + 0xfc17fb23, 0xfb5cfd0d, 0x001703e4, 0x077b09c4, + 0x09d2073c, 0x0251fc18, 0xf61cf203, 0xf118f3dc, + 0xf9d801aa, 0x09600eff, 0x110d0000, + }, { // 4.0 MHz + 0x00000001, 0xfffefff4, 0xffe1ffc8, 0xffbaffca, + 0x000b0082, 0x01170198, 0x01c10152, 0x0030fe7b, + 0xfc99fb24, 0xfac3fbe9, 0xfea5027f, 0x0683097f, + 0x0a560867, 0x03d2fd89, 0xf723f26f, 0xf0e8f341, + 0xf919010a, 0x09060ee5, 0x110d0000, + }, { // 4.1 MHz + 0x00010002, 0x0002fffb, 0xffe8ffca, 0xffacffa4, + 0xffcd0036, 0x00d70184, 0x01f601dc, 0x00ffff60, + 0xfd51fb6d, 0xfa6efaf5, 0xfd410103, 0x055708f9, + 0x0a9e0969, 0x0543ff02, 0xf842f2f5, 0xf0cef2b2, + 0xf85e006b, 0x08aa0ecb, 0x110d0000, + }, { // 4.2 MHz + 0x00010003, 0x00050003, 0xfff3ffd3, 0xffaaff8b, + 0xff95ffe5, 0x0080014a, 0x01fe023f, 0x01ba0050, + 0xfe35fbf8, 0xfa62fa3b, 0xfbf9ff7e, 0x04010836, + 0x0aa90a3d, 0x069f007f, 0xf975f395, 0xf0cbf231, + 0xf7a9ffcb, 0x084c0eaf, 0x110d0000, + }, { // 4.3 MHz + 0x00010003, 0x0008000a, 0x0000ffe4, 0xffb4ff81, + 0xff6aff96, 0x001c00f0, 0x01d70271, 0x0254013b, + 0xff36fcbd, 0xfa9ff9c5, 0xfadbfdfe, 0x028c073b, + 0x0a750adf, 0x07e101fa, 0xfab8f44e, 0xf0ddf1be, + 0xf6f9ff2b, 0x07ed0e94, 0x110d0000, + }, { // 4.4 MHz + 0x00000003, 0x0009000f, 0x000efff8, 0xffc9ff87, + 0xff52ff54, 0xffb5007e, 0x01860270, 0x02c00210, + 0x0044fdb2, 0xfb22f997, 0xf9f2fc90, 0x0102060f, + 0x0a050b4c, 0x0902036e, 0xfc0af51e, 0xf106f15a, + 0xf64efe8b, 0x078d0e77, 0x110d0000, + }, { // 4.5 MHz + 0x00000002, 0x00080012, 0x0019000e, 0xffe5ff9e, + 0xff4fff25, 0xff560000, 0x0112023b, 0x02f702c0, + 0x014dfec8, 0xfbe5f9b3, 0xf947fb41, 0xff7004b9, + 0x095a0b81, 0x0a0004d8, 0xfd65f603, 0xf144f104, + 0xf5aafdec, 0x072b0e5a, 0x110d0000, + }, { // 4.6 MHz + 0x00000001, 0x00060012, 0x00200022, 0x0005ffc1, + 0xff61ff10, 0xff09ff82, 0x008601d7, 0x02f50340, + 0x0241fff0, 0xfcddfa19, 0xf8e2fa1e, 0xfde30343, + 0x08790b7f, 0x0ad50631, 0xfec7f6fc, 0xf198f0bd, + 0xf50dfd4e, 0x06c90e3d, 0x110d0000, + }, { // 4.7 MHz + 0x0000ffff, 0x0003000f, 0x00220030, 0x0025ffed, + 0xff87ff15, 0xfed6ff10, 0xffed014c, 0x02b90386, + 0x03110119, 0xfdfefac4, 0xf8c6f92f, 0xfc6701b7, + 0x07670b44, 0x0b7e0776, 0x002df807, 0xf200f086, + 0xf477fcb1, 0x06650e1e, 0x110d0000, + }, { // 4.8 MHz + 0xfffffffe, 0xffff0009, 0x001e0038, 0x003f001b, + 0xffbcff36, 0xfec2feb6, 0xff5600a5, 0x0248038d, + 0x03b00232, 0xff39fbab, 0xf8f4f87f, 0xfb060020, + 0x062a0ad2, 0x0bf908a3, 0x0192f922, 0xf27df05e, + 0xf3e8fc14, 0x06000e00, 0x110d0000, + }, { // 4.9 MHz + 0xfffffffd, 0xfffc0002, 0x00160037, 0x00510046, + 0xfff9ff6d, 0xfed0fe7c, 0xfecefff0, 0x01aa0356, + 0x0413032b, 0x007ffcc5, 0xf96cf812, 0xf9cefe87, + 0x04c90a2c, 0x0c4309b4, 0x02f3fa4a, 0xf30ef046, + 0xf361fb7a, 0x059b0de0, 0x110d0000, + }, { // 5.0 MHz + 0xfffffffd, 0xfff9fffa, 0x000a002d, 0x00570067, + 0x0037ffb5, 0xfefffe68, 0xfe62ff3d, 0x00ec02e3, + 0x043503f6, 0x01befe05, 0xfa27f7ee, 0xf8c6fcf8, + 0x034c0954, 0x0c5c0aa4, 0x044cfb7e, 0xf3b1f03f, + 0xf2e2fae1, 0x05340dc0, 0x110d0000, + }, { // 5.1 MHz + 0x0000fffd, 0xfff8fff4, 0xfffd001e, 0x0051007b, + 0x006e0006, 0xff48fe7c, 0xfe1bfe9a, 0x001d023e, + 0x04130488, 0x02e6ff5b, 0xfb1ef812, 0xf7f7fb7f, + 0x01bc084e, 0x0c430b72, 0x059afcba, 0xf467f046, + 0xf26cfa4a, 0x04cd0da0, 0x110d0000, + }, { // 5.2 MHz + 0x0000fffe, 0xfff8ffef, 0xfff00009, 0x003f007f, + 0x00980056, 0xffa5feb6, 0xfe00fe15, 0xff4b0170, + 0x03b004d7, 0x03e800b9, 0xfc48f87f, 0xf768fa23, + 0x0022071f, 0x0bf90c1b, 0x06dafdfd, 0xf52df05e, + 0xf1fef9b5, 0x04640d7f, 0x110d0000, + }, { // 5.3 MHz + 0x0000ffff, 0xfff9ffee, 0xffe6fff3, 0x00250072, + 0x00af009c, 0x000cff10, 0xfe13fdb8, 0xfe870089, + 0x031104e1, 0x04b8020f, 0xfd98f92f, 0xf71df8f0, + 0xfe8805ce, 0x0b7e0c9c, 0x0808ff44, 0xf603f086, + 0xf19af922, 0x03fb0d5e, 0x110d0000, + }, { // 5.4 MHz + 0x00000001, 0xfffcffef, 0xffe0ffe0, 0x00050056, + 0x00b000d1, 0x0071ff82, 0xfe53fd8c, 0xfddfff99, + 0x024104a3, 0x054a034d, 0xff01fa1e, 0xf717f7ed, + 0xfcf50461, 0x0ad50cf4, 0x0921008d, 0xf6e7f0bd, + 0xf13ff891, 0x03920d3b, 0x110d0000, + }, { // 5.5 MHz + 0x00010002, 0xfffffff3, 0xffdeffd1, 0xffe5002f, + 0x009c00ed, 0x00cb0000, 0xfebafd94, 0xfd61feb0, + 0x014d0422, 0x05970464, 0x0074fb41, 0xf759f721, + 0xfb7502de, 0x0a000d21, 0x0a2201d4, 0xf7d9f104, + 0xf0edf804, 0x03280d19, 0x110d0000, + }, { // 5.6 MHz + 0x00010003, 0x0003fffa, 0xffe3ffc9, 0xffc90002, + 0x007500ef, 0x010e007e, 0xff3dfdcf, 0xfd16fddd, + 0x00440365, 0x059b0548, 0x01e3fc90, 0xf7dff691, + 0xfa0f014d, 0x09020d23, 0x0b0a0318, 0xf8d7f15a, + 0xf0a5f779, 0x02bd0cf6, 0x110d0000, + }, { // 5.7 MHz + 0x00010003, 0x00060001, 0xffecffc9, 0xffb4ffd4, + 0x004000d5, 0x013600f0, 0xffd3fe39, 0xfd04fd31, + 0xff360277, 0x055605ef, 0x033efdfe, 0xf8a5f642, + 0xf8cbffb6, 0x07e10cfb, 0x0bd50456, 0xf9dff1be, + 0xf067f6f2, 0x02520cd2, 0x110d0000, + }, { // 5.8 MHz + 0x00000003, 0x00080009, 0xfff8ffd2, 0xffaaffac, + 0x000200a3, 0x013c014a, 0x006dfec9, 0xfd2bfcb7, + 0xfe350165, 0x04cb0651, 0x0477ff7e, 0xf9a5f635, + 0xf7b1fe20, 0x069f0ca8, 0x0c81058b, 0xfaf0f231, + 0xf033f66d, 0x01e60cae, 0x110d0000, + }, { // 5.9 MHz + 0x00000002, 0x0009000e, 0x0005ffe1, 0xffacff90, + 0xffc5005f, 0x01210184, 0x00fcff72, 0xfd8afc77, + 0xfd51003f, 0x04020669, 0x05830103, 0xfad7f66b, + 0xf6c8fc93, 0x05430c2b, 0x0d0d06b5, 0xfc08f2b2, + 0xf00af5ec, 0x017b0c89, 0x110d0000, + }, { // 6.0 MHz + 0x00000001, 0x00070012, 0x0012fff5, 0xffbaff82, + 0xff8e000f, 0x00e80198, 0x01750028, 0xfe18fc75, + 0xfc99ff15, 0x03050636, 0x0656027f, 0xfc32f6e2, + 0xf614fb17, 0x03d20b87, 0x0d7707d2, 0xfd26f341, + 0xefeaf56f, 0x010f0c64, 0x110d0000, + }, { // 6.1 MHz + 0xffff0000, 0x00050012, 0x001c000b, 0xffd1ff84, + 0xff66ffbe, 0x00960184, 0x01cd00da, 0xfeccfcb2, + 0xfc17fdf9, 0x01e005bc, 0x06e703e4, 0xfdabf798, + 0xf599f9b3, 0x02510abd, 0x0dbf08df, 0xfe48f3dc, + 0xefd5f4f6, 0x00a20c3e, 0x110d0000, + }, { // 6.2 MHz + 0xfffffffe, 0x0002000f, 0x0021001f, 0xfff0ff97, + 0xff50ff74, 0x0034014a, 0x01fa0179, 0xff97fd2a, + 0xfbd3fcfa, 0x00a304fe, 0x07310525, 0xff37f886, + 0xf55cf86e, 0x00c709d0, 0x0de209db, 0xff6df484, + 0xefcbf481, 0x00360c18, 0x110d0000, + }, { // 6.3 MHz + 0xfffffffd, 0xfffe000a, 0x0021002f, 0x0010ffb8, + 0xff50ff3b, 0xffcc00f0, 0x01fa01fa, 0x0069fdd4, + 0xfbd3fc26, 0xff5d0407, 0x07310638, 0x00c9f9a8, + 0xf55cf74e, 0xff3908c3, 0x0de20ac3, 0x0093f537, + 0xefcbf410, 0xffca0bf2, 0x110d0000, + }, { // 6.4 MHz + 0xfffffffd, 0xfffb0003, 0x001c0037, 0x002fffe2, + 0xff66ff17, 0xff6a007e, 0x01cd0251, 0x0134fea5, + 0xfc17fb8b, 0xfe2002e0, 0x06e70713, 0x0255faf5, + 0xf599f658, 0xfdaf0799, 0x0dbf0b96, 0x01b8f5f5, + 0xefd5f3a3, 0xff5e0bca, 0x110d0000, + }, { // 6.5 MHz + 0x0000fffd, 0xfff9fffb, 0x00120037, 0x00460010, + 0xff8eff0f, 0xff180000, 0x01750276, 0x01e8ff8d, + 0xfc99fb31, 0xfcfb0198, 0x065607ad, 0x03cefc64, + 0xf614f592, 0xfc2e0656, 0x0d770c52, 0x02daf6bd, + 0xefeaf33b, 0xfef10ba3, 0x110d0000, + }, { // 6.6 MHz + 0x0000fffe, 0xfff7fff5, 0x0005002f, 0x0054003c, + 0xffc5ff22, 0xfedfff82, 0x00fc0267, 0x0276007e, + 0xfd51fb1c, 0xfbfe003e, 0x05830802, 0x0529fdec, + 0xf6c8f4fe, 0xfabd04ff, 0x0d0d0cf6, 0x03f8f78f, + 0xf00af2d7, 0xfe850b7b, 0x110d0000, + }, { // 6.7 MHz + 0x0000ffff, 0xfff8fff0, 0xfff80020, 0x00560060, + 0x0002ff4e, 0xfec4ff10, 0x006d0225, 0x02d50166, + 0xfe35fb4e, 0xfb35fee1, 0x0477080e, 0x065bff82, + 0xf7b1f4a0, 0xf9610397, 0x0c810d80, 0x0510f869, + 0xf033f278, 0xfe1a0b52, 0x110d0000, + }, { // 6.8 MHz + 0x00010000, 0xfffaffee, 0xffec000c, 0x004c0078, + 0x0040ff8e, 0xfecafeb6, 0xffd301b6, 0x02fc0235, + 0xff36fbc5, 0xfaaafd90, 0x033e07d2, 0x075b011b, + 0xf8cbf47a, 0xf81f0224, 0x0bd50def, 0x0621f94b, + 0xf067f21e, 0xfdae0b29, 0x110d0000, + }, { // 6.9 MHz + 0x00010001, 0xfffdffef, 0xffe3fff6, 0x0037007f, + 0x0075ffdc, 0xfef2fe7c, 0xff3d0122, 0x02ea02dd, + 0x0044fc79, 0xfa65fc5d, 0x01e3074e, 0x082102ad, + 0xfa0ff48c, 0xf6fe00a9, 0x0b0a0e43, 0x0729fa33, + 0xf0a5f1c9, 0xfd430b00, 0x110d0000, + }, { // 7.0 MHz + 0x00010002, 0x0001fff3, 0xffdeffe2, 0x001b0076, + 0x009c002d, 0xff35fe68, 0xfeba0076, 0x029f0352, + 0x014dfd60, 0xfa69fb53, 0x00740688, 0x08a7042d, + 0xfb75f4d6, 0xf600ff2d, 0x0a220e7a, 0x0827fb22, + 0xf0edf17a, 0xfcd80ad6, 0x110d0000, + }, { // 7.1 MHz + 0x00000003, 0x0004fff9, 0xffe0ffd2, 0xfffb005e, + 0x00b0007a, 0xff8ffe7c, 0xfe53ffc1, 0x0221038c, + 0x0241fe6e, 0xfab6fa80, 0xff010587, 0x08e90590, + 0xfcf5f556, 0xf52bfdb3, 0x09210e95, 0x0919fc15, + 0xf13ff12f, 0xfc6e0aab, 0x110d0000, + }, { // 7.2 MHz + 0x00000003, 0x00070000, 0xffe6ffc9, 0xffdb0039, + 0x00af00b8, 0xfff4feb6, 0xfe13ff10, 0x01790388, + 0x0311ff92, 0xfb48f9ed, 0xfd980453, 0x08e306cd, + 0xfe88f60a, 0xf482fc40, 0x08080e93, 0x09fdfd0c, + 0xf19af0ea, 0xfc050a81, 0x110d0000, + }, { // 7.3 MHz + 0x00000002, 0x00080008, 0xfff0ffc9, 0xffc1000d, + 0x009800e2, 0x005bff10, 0xfe00fe74, 0x00b50345, + 0x03b000bc, 0xfc18f9a1, 0xfc4802f9, 0x089807dc, + 0x0022f6f0, 0xf407fada, 0x06da0e74, 0x0ad3fe06, + 0xf1fef0ab, 0xfb9c0a55, 0x110d0000, + }, { // 7.4 MHz + 0x00000001, 0x0008000e, 0xfffdffd0, 0xffafffdf, + 0x006e00f2, 0x00b8ff82, 0xfe1bfdf8, 0xffe302c8, + 0x041301dc, 0xfd1af99e, 0xfb1e0183, 0x080908b5, + 0x01bcf801, 0xf3bdf985, 0x059a0e38, 0x0b99ff03, + 0xf26cf071, 0xfb330a2a, 0x110d0000, + }, { // 7.5 MHz + 0xffff0000, 0x00070011, 0x000affdf, 0xffa9ffb5, + 0x003700e6, 0x01010000, 0xfe62fda8, 0xff140219, + 0x043502e1, 0xfe42f9e6, 0xfa270000, 0x073a0953, + 0x034cf939, 0xf3a4f845, 0x044c0de1, 0x0c4f0000, + 0xf2e2f03c, 0xfacc09fe, 0x110d0000, + }, { // 7.6 MHz + 0xffffffff, 0x00040012, 0x0016fff3, 0xffafff95, + 0xfff900c0, 0x0130007e, 0xfecefd89, 0xfe560146, + 0x041303bc, 0xff81fa76, 0xf96cfe7d, 0x063209b1, + 0x04c9fa93, 0xf3bdf71e, 0x02f30d6e, 0x0cf200fd, + 0xf361f00e, 0xfa6509d1, 0x110d0000, + }, { // 7.7 MHz + 0xfffffffe, 0x00010010, 0x001e0008, 0xffc1ff84, + 0xffbc0084, 0x013e00f0, 0xff56fd9f, 0xfdb8005c, + 0x03b00460, 0x00c7fb45, 0xf8f4fd07, 0x04fa09ce, + 0x062afc07, 0xf407f614, 0x01920ce0, 0x0d8301fa, + 0xf3e8efe5, 0xfa0009a4, 0x110d0000, + }, { // 7.8 MHz + 0x0000fffd, 0xfffd000b, 0x0022001d, 0xffdbff82, + 0xff870039, 0x012a014a, 0xffedfde7, 0xfd47ff6b, + 0x031104c6, 0x0202fc4c, 0xf8c6fbad, 0x039909a7, + 0x0767fd8e, 0xf482f52b, 0x002d0c39, 0x0e0002f4, + 0xf477efc2, 0xf99b0977, 0x110d0000, + }, { // 7.9 MHz + 0x0000fffd, 0xfffa0004, 0x0020002d, 0xfffbff91, + 0xff61ffe8, 0x00f70184, 0x0086fe5c, 0xfd0bfe85, + 0x024104e5, 0x0323fd7d, 0xf8e2fa79, 0x021d093f, + 0x0879ff22, 0xf52bf465, 0xfec70b79, 0x0e6803eb, + 0xf50defa5, 0xf937094a, 0x110d0000, + }, { // 8.0 MHz + 0x0000fffe, 0xfff8fffd, 0x00190036, 0x001bffaf, + 0xff4fff99, 0x00aa0198, 0x0112fef3, 0xfd09fdb9, + 0x014d04be, 0x041bfecc, 0xf947f978, 0x00900897, + 0x095a00b9, 0xf600f3c5, 0xfd650aa3, 0x0ebc04de, + 0xf5aaef8e, 0xf8d5091c, 0x110d0000, + }, { // 8.1 MHz + 0x0000ffff, 0xfff7fff6, 0x000e0038, 0x0037ffd7, + 0xff52ff56, 0x004b0184, 0x0186ffa1, 0xfd40fd16, + 0x00440452, 0x04de0029, 0xf9f2f8b2, 0xfefe07b5, + 0x0a05024d, 0xf6fef34d, 0xfc0a09b8, 0x0efa05cd, + 0xf64eef7d, 0xf87308ed, 0x110d0000, + }, { // 8.2 MHz + 0x00010000, 0xfff8fff0, 0x00000031, 0x004c0005, + 0xff6aff27, 0xffe4014a, 0x01d70057, 0xfdacfca6, + 0xff3603a7, 0x05610184, 0xfadbf82e, 0xfd74069f, + 0x0a7503d6, 0xf81ff2ff, 0xfab808b9, 0x0f2306b5, + 0xf6f9ef72, 0xf81308bf, 0x110d0000, + }, { // 8.3 MHz + 0x00010001, 0xfffbffee, 0xfff30022, 0x00560032, + 0xff95ff10, 0xff8000f0, 0x01fe0106, 0xfe46fc71, + 0xfe3502c7, 0x059e02ce, 0xfbf9f7f2, 0xfbff055b, + 0x0aa9054c, 0xf961f2db, 0xf97507aa, 0x0f350797, + 0xf7a9ef6d, 0xf7b40890, 0x110d0000, + }, { // 8.4 MHz + 0x00010002, 0xfffeffee, 0xffe8000f, 0x00540058, + 0xffcdff14, 0xff29007e, 0x01f6019e, 0xff01fc7c, + 0xfd5101bf, 0x059203f6, 0xfd41f7fe, 0xfaa903f3, + 0x0a9e06a9, 0xfabdf2e2, 0xf842068b, 0x0f320871, + 0xf85eef6e, 0xf7560860, 0x110d0000, + }, { // 8.5 MHz + 0x00000003, 0x0002fff2, 0xffe1fff9, 0x00460073, + 0x000bff34, 0xfee90000, 0x01c10215, 0xffd0fcc5, + 0xfc99009d, 0x053d04f1, 0xfea5f853, 0xf97d0270, + 0x0a5607e4, 0xfc2ef314, 0xf723055f, 0x0f180943, + 0xf919ef75, 0xf6fa0830, 0x110d0000, + }, { // 8.6 MHz + 0x00000003, 0x0005fff8, 0xffdeffe4, 0x002f007f, + 0x0048ff6b, 0xfec7ff82, 0x0163025f, 0x00a2fd47, + 0xfc17ff73, 0x04a405b2, 0x0017f8ed, 0xf88500dc, + 0x09d208f9, 0xfdaff370, 0xf61c0429, 0x0ee80a0b, + 0xf9d8ef82, 0xf6a00800, 0x110d0000, + }, { // 8.7 MHz + 0x00000003, 0x0007ffff, 0xffe1ffd4, 0x0010007a, + 0x007cffb2, 0xfec6ff10, 0x00e60277, 0x0168fdf9, + 0xfbd3fe50, 0x03ce0631, 0x0188f9c8, 0xf7c7ff43, + 0x091509e3, 0xff39f3f6, 0xf52d02ea, 0x0ea30ac9, + 0xfa9bef95, 0xf64607d0, 0x110d0000, + }, { // 8.8 MHz + 0x00000002, 0x00090007, 0xffe9ffca, 0xfff00065, + 0x00a10003, 0xfee6feb6, 0x0053025b, 0x0213fed0, + 0xfbd3fd46, 0x02c70668, 0x02eafadb, 0xf74bfdae, + 0x08230a9c, 0x00c7f4a3, 0xf45b01a6, 0x0e480b7c, + 0xfb61efae, 0xf5ef079f, 0x110d0000, + }, { // 8.9 MHz + 0xffff0000, 0x0008000d, 0xfff5ffc8, 0xffd10043, + 0x00b20053, 0xff24fe7c, 0xffb9020c, 0x0295ffbb, + 0xfc17fc64, 0x019b0654, 0x042dfc1c, 0xf714fc2a, + 0x07020b21, 0x0251f575, 0xf3a7005e, 0x0dd80c24, + 0xfc2aefcd, 0xf599076e, 0x110d0000, + }, { // 9.0 MHz + 0xffffffff, 0x00060011, 0x0002ffcf, 0xffba0018, + 0x00ad009a, 0xff79fe68, 0xff260192, 0x02e500ab, + 0xfc99fbb6, 0x005b05f7, 0x0545fd81, 0xf723fabf, + 0x05b80b70, 0x03d2f669, 0xf313ff15, 0x0d550cbf, + 0xfcf6eff2, 0xf544073d, 0x110d0000, + }, { // 9.1 MHz + 0xfffffffe, 0x00030012, 0x000fffdd, 0xffacffea, + 0x009300cf, 0xffdcfe7c, 0xfea600f7, 0x02fd0190, + 0xfd51fb46, 0xff150554, 0x0627fefd, 0xf778f978, + 0x044d0b87, 0x0543f77d, 0xf2a0fdcf, 0x0cbe0d4e, + 0xfdc4f01d, 0xf4f2070b, 0x110d0000, + }, { // 9.2 MHz + 0x0000fffd, 0x00000010, 0x001afff0, 0xffaaffbf, + 0x006700ed, 0x0043feb6, 0xfe460047, 0x02db0258, + 0xfe35fb1b, 0xfddc0473, 0x06c90082, 0xf811f85e, + 0x02c90b66, 0x069ff8ad, 0xf250fc8d, 0x0c140dcf, + 0xfe93f04d, 0xf4a106d9, 0x110d0000, + }, { // 9.3 MHz + 0x0000fffd, 0xfffc000c, 0x00200006, 0xffb4ff9c, + 0x002f00ef, 0x00a4ff10, 0xfe0dff92, 0x028102f7, + 0xff36fb37, 0xfcbf035e, 0x07260202, 0xf8e8f778, + 0x01340b0d, 0x07e1f9f4, 0xf223fb51, 0x0b590e42, + 0xff64f083, 0xf45206a7, 0x110d0000, + }, { // 9.4 MHz + 0x0000fffd, 0xfff90005, 0x0022001a, 0xffc9ff86, + 0xfff000d7, 0x00f2ff82, 0xfe01fee5, 0x01f60362, + 0x0044fb99, 0xfbcc0222, 0x07380370, 0xf9f7f6cc, + 0xff990a7e, 0x0902fb50, 0xf21afa1f, 0x0a8d0ea6, + 0x0034f0bf, 0xf4050675, 0x110d0000, + }, { // 9.5 MHz + 0x0000fffe, 0xfff8fffe, 0x001e002b, 0xffe5ff81, + 0xffb400a5, 0x01280000, 0xfe24fe50, 0x01460390, + 0x014dfc3a, 0xfb1000ce, 0x070104bf, 0xfb37f65f, + 0xfe0009bc, 0x0a00fcbb, 0xf235f8f8, 0x09b20efc, + 0x0105f101, 0xf3ba0642, 0x110d0000, + }, { // 9.6 MHz + 0x0001ffff, 0xfff8fff7, 0x00150036, 0x0005ff8c, + 0xff810061, 0x013d007e, 0xfe71fddf, 0x007c0380, + 0x0241fd13, 0xfa94ff70, 0x068005e2, 0xfc9bf633, + 0xfc7308ca, 0x0ad5fe30, 0xf274f7e0, 0x08c90f43, + 0x01d4f147, 0xf371060f, 0x110d0000, + }, { // 9.7 MHz + 0x00010001, 0xfff9fff1, 0x00090038, 0x0025ffa7, + 0xff5e0012, 0x013200f0, 0xfee3fd9b, 0xffaa0331, + 0x0311fe15, 0xfa60fe18, 0x05bd06d1, 0xfe1bf64a, + 0xfafa07ae, 0x0b7effab, 0xf2d5f6d7, 0x07d30f7a, + 0x02a3f194, 0xf32905dc, 0x110d0000, + }, { // 9.8 MHz + 0x00010002, 0xfffcffee, 0xfffb0032, 0x003fffcd, + 0xff4effc1, 0x0106014a, 0xff6efd8a, 0xfedd02aa, + 0x03b0ff34, 0xfa74fcd7, 0x04bf0781, 0xffaaf6a3, + 0xf99e066b, 0x0bf90128, 0xf359f5e1, 0x06d20fa2, + 0x0370f1e5, 0xf2e405a8, 0x110d0000, + }, { // 9.9 MHz + 0x00000003, 0xffffffee, 0xffef0024, 0x0051fffa, + 0xff54ff77, 0x00be0184, 0x0006fdad, 0xfe2701f3, + 0x0413005e, 0xfad1fbba, 0x039007ee, 0x013bf73d, + 0xf868050a, 0x0c4302a1, 0xf3fdf4fe, 0x05c70fba, + 0x043bf23c, 0xf2a10575, 0x110d0000, + }, { // 10.0 MHz + 0x00000003, 0x0003fff1, 0xffe50011, 0x00570027, + 0xff70ff3c, 0x00620198, 0x009efe01, 0xfd95011a, + 0x04350183, 0xfb71fad0, 0x023c0812, 0x02c3f811, + 0xf75e0390, 0x0c5c0411, 0xf4c1f432, 0x04b30fc1, + 0x0503f297, 0xf2610541, 0x110d0000, + }, { // 10.1 MHz + 0x00000003, 0x0006fff7, 0xffdffffc, 0x00510050, + 0xff9dff18, 0xfffc0184, 0x0128fe80, 0xfd32002e, + 0x04130292, 0xfc4dfa21, 0x00d107ee, 0x0435f91c, + 0xf6850205, 0x0c430573, 0xf5a1f37d, 0x03990fba, + 0x05c7f2f8, 0xf222050d, 0x110d0000, + }, { // 10.2 MHz + 0x00000002, 0x0008fffe, 0xffdfffe7, 0x003f006e, + 0xffd6ff0f, 0xff96014a, 0x0197ff1f, 0xfd05ff3e, + 0x03b0037c, 0xfd59f9b7, 0xff5d0781, 0x0585fa56, + 0xf5e4006f, 0x0bf906c4, 0xf69df2e0, 0x02790fa2, + 0x0688f35d, 0xf1e604d8, 0x110d0000, + }, { // 10.3 MHz + 0xffff0001, 0x00090005, 0xffe4ffd6, 0x0025007e, + 0x0014ff20, 0xff3c00f0, 0x01e1ffd0, 0xfd12fe5c, + 0x03110433, 0xfe88f996, 0xfdf106d1, 0x06aafbb7, + 0xf57efed8, 0x0b7e07ff, 0xf7b0f25e, 0x01560f7a, + 0x0745f3c7, 0xf1ac04a4, 0x110d0000, + }, { // 10.4 MHz + 0xffffffff, 0x0008000c, 0xffedffcb, 0x0005007d, + 0x0050ff4c, 0xfef6007e, 0x01ff0086, 0xfd58fd97, + 0x024104ad, 0xffcaf9c0, 0xfc9905e2, 0x079afd35, + 0xf555fd46, 0x0ad50920, 0xf8d9f1f6, 0x00310f43, + 0x07fdf435, 0xf174046f, 0x110d0000, + }, { // 10.5 MHz + 0xfffffffe, 0x00050011, 0xfffaffc8, 0xffe5006b, + 0x0082ff8c, 0xfecc0000, 0x01f00130, 0xfdd2fcfc, + 0x014d04e3, 0x010efa32, 0xfb6404bf, 0x084efec5, + 0xf569fbc2, 0x0a000a23, 0xfa15f1ab, 0xff0b0efc, + 0x08b0f4a7, 0xf13f043a, 0x110d0000, + }, { // 10.6 MHz + 0x0000fffd, 0x00020012, 0x0007ffcd, 0xffc9004c, + 0x00a4ffd9, 0xfec3ff82, 0x01b401c1, 0xfe76fc97, + 0x004404d2, 0x0245fae8, 0xfa5f0370, 0x08c1005f, + 0xf5bcfa52, 0x09020b04, 0xfb60f17b, 0xfde70ea6, + 0x095df51e, 0xf10c0405, 0x110d0000, + }, { // 10.7 MHz + 0x0000fffd, 0xffff0011, 0x0014ffdb, 0xffb40023, + 0x00b2002a, 0xfedbff10, 0x0150022d, 0xff38fc6f, + 0xff36047b, 0x035efbda, 0xf9940202, 0x08ee01f5, + 0xf649f8fe, 0x07e10bc2, 0xfcb6f169, 0xfcc60e42, + 0x0a04f599, 0xf0db03d0, 0x110d0000, + }, { // 10.8 MHz + 0x0000fffd, 0xfffb000d, 0x001dffed, 0xffaafff5, + 0x00aa0077, 0xff13feb6, 0x00ce026b, 0x000afc85, + 0xfe3503e3, 0x044cfcfb, 0xf90c0082, 0x08d5037f, + 0xf710f7cc, 0x069f0c59, 0xfe16f173, 0xfbaa0dcf, + 0x0aa5f617, 0xf0ad039b, 0x110d0000, + }, { // 10.9 MHz + 0x0000fffe, 0xfff90006, 0x00210003, 0xffacffc8, + 0x008e00b6, 0xff63fe7c, 0x003a0275, 0x00dafcda, + 0xfd510313, 0x0501fe40, 0xf8cbfefd, 0x087604f0, + 0xf80af6c2, 0x05430cc8, 0xff7af19a, 0xfa940d4e, + 0x0b3ff699, 0xf0810365, 0x110d0000, + }, { // 11.0 MHz + 0x0001ffff, 0xfff8ffff, 0x00210018, 0xffbaffa3, + 0x006000e1, 0xffc4fe68, 0xffa0024b, 0x019afd66, + 0xfc990216, 0x0575ff99, 0xf8d4fd81, 0x07d40640, + 0xf932f5e6, 0x03d20d0d, 0x00dff1de, 0xf9860cbf, + 0x0bd1f71e, 0xf058032f, 0x110d0000, + }, { // 11.1 MHz + 0x00010000, 0xfff8fff8, 0x001b0029, 0xffd1ff8a, + 0x002600f2, 0x002cfe7c, 0xff0f01f0, 0x023bfe20, + 0xfc1700fa, 0x05a200f7, 0xf927fc1c, 0x06f40765, + 0xfa82f53b, 0x02510d27, 0x0243f23d, 0xf8810c24, + 0x0c5cf7a7, 0xf03102fa, 0x110d0000, + }, { // 11.2 MHz + 0x00010002, 0xfffafff2, 0x00110035, 0xfff0ff81, + 0xffe700e7, 0x008ffeb6, 0xfe94016d, 0x02b0fefb, + 0xfbd3ffd1, 0x05850249, 0xf9c1fadb, 0x05de0858, + 0xfbf2f4c4, 0x00c70d17, 0x03a0f2b8, 0xf7870b7c, + 0x0cdff833, 0xf00d02c4, 0x110d0000, + }, { // 11.3 MHz + 0x00000003, 0xfffdffee, 0x00040038, 0x0010ff88, + 0xffac00c2, 0x00e2ff10, 0xfe3900cb, 0x02f1ffe9, + 0xfbd3feaa, 0x05210381, 0xfa9cf9c8, 0x04990912, + 0xfd7af484, 0xff390cdb, 0x04f4f34d, 0xf69a0ac9, + 0x0d5af8c1, 0xefec028e, 0x110d0000, + }, { // 11.4 MHz + 0x00000003, 0x0000ffee, 0xfff60033, 0x002fff9f, + 0xff7b0087, 0x011eff82, 0xfe080018, 0x02f900d8, + 0xfc17fd96, 0x04790490, 0xfbadf8ed, 0x032f098e, + 0xff10f47d, 0xfdaf0c75, 0x063cf3fc, 0xf5ba0a0b, + 0x0dccf952, 0xefcd0258, 0x110d0000, + }, { // 11.5 MHz + 0x00000003, 0x0004fff1, 0xffea0026, 0x0046ffc3, + 0xff5a003c, 0x013b0000, 0xfe04ff63, 0x02c801b8, + 0xfc99fca6, 0x0397056a, 0xfcecf853, 0x01ad09c9, + 0x00acf4ad, 0xfc2e0be7, 0x0773f4c2, 0xf4e90943, + 0x0e35f9e6, 0xefb10221, 0x110d0000, + }, { // 11.6 MHz + 0x00000002, 0x0007fff6, 0xffe20014, 0x0054ffee, + 0xff4effeb, 0x0137007e, 0xfe2efebb, 0x0260027a, + 0xfd51fbe6, 0x02870605, 0xfe4af7fe, 0x001d09c1, + 0x0243f515, 0xfabd0b32, 0x0897f59e, 0xf4280871, + 0x0e95fa7c, 0xef9701eb, 0x110d0000, + }, { // 11.7 MHz + 0xffff0001, 0x0008fffd, 0xffdeffff, 0x0056001d, + 0xff57ff9c, 0x011300f0, 0xfe82fe2e, 0x01ca0310, + 0xfe35fb62, 0x0155065a, 0xffbaf7f2, 0xfe8c0977, + 0x03cef5b2, 0xf9610a58, 0x09a5f68f, 0xf3790797, + 0x0eebfb14, 0xef8001b5, 0x110d0000, + }, { // 11.8 MHz + 0xffff0000, 0x00080004, 0xffe0ffe9, 0x004c0047, + 0xff75ff58, 0x00d1014a, 0xfef9fdc8, 0x0111036f, + 0xff36fb21, 0x00120665, 0x012df82e, 0xfd0708ec, + 0x0542f682, 0xf81f095c, 0x0a9af792, 0xf2db06b5, + 0x0f38fbad, 0xef6c017e, 0x110d0000, + }, { // 11.9 MHz + 0xffffffff, 0x0007000b, 0xffe7ffd8, 0x00370068, + 0xffa4ff28, 0x00790184, 0xff87fd91, 0x00430392, + 0x0044fb26, 0xfece0626, 0x0294f8b2, 0xfb990825, + 0x0698f77f, 0xf6fe0842, 0x0b73f8a7, 0xf25105cd, + 0x0f7bfc48, 0xef5a0148, 0x110d0000, + }, { // 12.0 MHz + 0x0000fffe, 0x00050010, 0xfff2ffcc, 0x001b007b, + 0xffdfff10, 0x00140198, 0x0020fd8e, 0xff710375, + 0x014dfb73, 0xfd9a059f, 0x03e0f978, 0xfa4e0726, + 0x07c8f8a7, 0xf600070c, 0x0c2ff9c9, 0xf1db04de, + 0x0fb4fce5, 0xef4b0111, 0x110d0000, + }, { // 12.1 MHz + 0x0000fffd, 0x00010012, 0xffffffc8, 0xfffb007e, + 0x001dff14, 0xffad0184, 0x00b7fdbe, 0xfea9031b, + 0x0241fc01, 0xfc8504d6, 0x0504fa79, 0xf93005f6, + 0x08caf9f2, 0xf52b05c0, 0x0ccbfaf9, 0xf17903eb, + 0x0fe3fd83, 0xef3f00db, 0x110d0000, + }, { // 12.2 MHz + 0x0000fffd, 0xfffe0011, 0x000cffcc, 0xffdb0071, + 0x0058ff32, 0xff4f014a, 0x013cfe1f, 0xfdfb028a, + 0x0311fcc9, 0xfb9d03d6, 0x05f4fbad, 0xf848049d, + 0x0999fb5b, 0xf4820461, 0x0d46fc32, 0xf12d02f4, + 0x1007fe21, 0xef3600a4, 0x110d0000, + }, { // 12.3 MHz + 0x0000fffe, 0xfffa000e, 0x0017ffd9, 0xffc10055, + 0x0088ff68, 0xff0400f0, 0x01a6fea7, 0xfd7501cc, + 0x03b0fdc0, 0xfaef02a8, 0x06a7fd07, 0xf79d0326, + 0x0a31fcda, 0xf40702f3, 0x0d9ffd72, 0xf0f601fa, + 0x1021fec0, 0xef2f006d, 0x110d0000, + }, { // 12.4 MHz + 0x0001ffff, 0xfff80007, 0x001fffeb, 0xffaf002d, + 0x00a8ffb0, 0xfed3007e, 0x01e9ff4c, 0xfd2000ee, + 0x0413fed8, 0xfa82015c, 0x0715fe7d, 0xf7340198, + 0x0a8dfe69, 0xf3bd017c, 0x0dd5feb8, 0xf0d500fd, + 0x1031ff60, 0xef2b0037, 0x110d0000, + }, { // 12.5 MHz + 0x00010000, 0xfff70000, 0x00220000, 0xffa90000, + 0x00b30000, 0xfec20000, 0x02000000, 0xfd030000, + 0x04350000, 0xfa5e0000, 0x073b0000, 0xf7110000, + 0x0aac0000, 0xf3a40000, 0x0de70000, 0xf0c90000, + 0x10360000, 0xef290000, 0x110d0000, + }, { // 12.6 MHz + 0x00010001, 0xfff8fff9, 0x001f0015, 0xffafffd3, + 0x00a80050, 0xfed3ff82, 0x01e900b4, 0xfd20ff12, + 0x04130128, 0xfa82fea4, 0x07150183, 0xf734fe68, + 0x0a8d0197, 0xf3bdfe84, 0x0dd50148, 0xf0d5ff03, + 0x103100a0, 0xef2bffc9, 0x110d0000, + }, { // 12.7 MHz + 0x00000002, 0xfffafff2, 0x00170027, 0xffc1ffab, + 0x00880098, 0xff04ff10, 0x01a60159, 0xfd75fe34, + 0x03b00240, 0xfaeffd58, 0x06a702f9, 0xf79dfcda, + 0x0a310326, 0xf407fd0d, 0x0d9f028e, 0xf0f6fe06, + 0x10210140, 0xef2fff93, 0x110d0000, + }, { // 12.8 MHz + 0x00000003, 0xfffeffef, 0x000c0034, 0xffdbff8f, + 0x005800ce, 0xff4ffeb6, 0x013c01e1, 0xfdfbfd76, + 0x03110337, 0xfb9dfc2a, 0x05f40453, 0xf848fb63, + 0x099904a5, 0xf482fb9f, 0x0d4603ce, 0xf12dfd0c, + 0x100701df, 0xef36ff5c, 0x110d0000, + }, { // 12.9 MHz + 0x00000003, 0x0001ffee, 0xffff0038, 0xfffbff82, + 0x001d00ec, 0xffadfe7c, 0x00b70242, 0xfea9fce5, + 0x024103ff, 0xfc85fb2a, 0x05040587, 0xf930fa0a, + 0x08ca060e, 0xf52bfa40, 0x0ccb0507, 0xf179fc15, + 0x0fe3027d, 0xef3fff25, 0x110d0000, + }, { // 13.0 MHz + 0x00000002, 0x0005fff0, 0xfff20034, 0x001bff85, + 0xffdf00f0, 0x0014fe68, 0x00200272, 0xff71fc8b, + 0x014d048d, 0xfd9afa61, 0x03e00688, 0xfa4ef8da, + 0x07c80759, 0xf600f8f4, 0x0c2f0637, 0xf1dbfb22, + 0x0fb4031b, 0xef4bfeef, 0x110d0000, + }, { // 13.1 MHz + 0xffff0001, 0x0007fff5, 0xffe70028, 0x0037ff98, + 0xffa400d8, 0x0079fe7c, 0xff87026f, 0x0043fc6e, + 0x004404da, 0xfecef9da, 0x0294074e, 0xfb99f7db, + 0x06980881, 0xf6fef7be, 0x0b730759, 0xf251fa33, + 0x0f7b03b8, 0xef5afeb8, 0x110d0000, + }, { // 13.2 MHz + 0xffff0000, 0x0008fffc, 0xffe00017, 0x004cffb9, + 0xff7500a8, 0x00d1feb6, 0xfef90238, 0x0111fc91, + 0xff3604df, 0x0012f99b, 0x012d07d2, 0xfd07f714, + 0x0542097e, 0xf81ff6a4, 0x0a9a086e, 0xf2dbf94b, + 0x0f380453, 0xef6cfe82, 0x110d0000, + }, { // 13.3 MHz + 0xffffffff, 0x00080003, 0xffde0001, 0x0056ffe3, + 0xff570064, 0x0113ff10, 0xfe8201d2, 0x01cafcf0, + 0xfe35049e, 0x0155f9a6, 0xffba080e, 0xfe8cf689, + 0x03ce0a4e, 0xf961f5a8, 0x09a50971, 0xf379f869, + 0x0eeb04ec, 0xef80fe4b, 0x110d0000, + }, { // 13.4 MHz + 0x0000fffe, 0x0007000a, 0xffe2ffec, 0x00540012, + 0xff4e0015, 0x0137ff82, 0xfe2e0145, 0x0260fd86, + 0xfd51041a, 0x0287f9fb, 0xfe4a0802, 0x001df63f, + 0x02430aeb, 0xfabdf4ce, 0x08970a62, 0xf428f78f, + 0x0e950584, 0xef97fe15, 0x110d0000, + }, { // 13.5 MHz + 0x0000fffd, 0x0004000f, 0xffeaffda, 0x0046003d, + 0xff5affc4, 0x013b0000, 0xfe04009d, 0x02c8fe48, + 0xfc99035a, 0x0397fa96, 0xfcec07ad, 0x01adf637, + 0x00ac0b53, 0xfc2ef419, 0x07730b3e, 0xf4e9f6bd, + 0x0e35061a, 0xefb1fddf, 0x110d0000, + }, { // 13.6 MHz + 0x0000fffd, 0x00000012, 0xfff6ffcd, 0x002f0061, + 0xff7bff79, 0x011e007e, 0xfe08ffe8, 0x02f9ff28, + 0xfc17026a, 0x0479fb70, 0xfbad0713, 0x032ff672, + 0xff100b83, 0xfdaff38b, 0x063c0c04, 0xf5baf5f5, + 0x0dcc06ae, 0xefcdfda8, 0x110d0000, + }, { // 13.7 MHz + 0x0000fffd, 0xfffd0012, 0x0004ffc8, 0x00100078, + 0xffacff3e, 0x00e200f0, 0xfe39ff35, 0x02f10017, + 0xfbd30156, 0x0521fc7f, 0xfa9c0638, 0x0499f6ee, + 0xfd7a0b7c, 0xff39f325, 0x04f40cb3, 0xf69af537, + 0x0d5a073f, 0xefecfd72, 0x110d0000, + }, { // 13.8 MHz + 0x0001fffe, 0xfffa000e, 0x0011ffcb, 0xfff0007f, + 0xffe7ff19, 0x008f014a, 0xfe94fe93, 0x02b00105, + 0xfbd3002f, 0x0585fdb7, 0xf9c10525, 0x05def7a8, + 0xfbf20b3c, 0x00c7f2e9, 0x03a00d48, 0xf787f484, + 0x0cdf07cd, 0xf00dfd3c, 0x110d0000, + }, { // 13.9 MHz + 0x00010000, 0xfff80008, 0x001bffd7, 0xffd10076, + 0x0026ff0e, 0x002c0184, 0xff0ffe10, 0x023b01e0, + 0xfc17ff06, 0x05a2ff09, 0xf92703e4, 0x06f4f89b, + 0xfa820ac5, 0x0251f2d9, 0x02430dc3, 0xf881f3dc, + 0x0c5c0859, 0xf031fd06, 0x110d0000, + }, { // 14.0 MHz + 0x00010001, 0xfff80001, 0x0021ffe8, 0xffba005d, + 0x0060ff1f, 0xffc40198, 0xffa0fdb5, 0x019a029a, + 0xfc99fdea, 0x05750067, 0xf8d4027f, 0x07d4f9c0, + 0xf9320a1a, 0x03d2f2f3, 0x00df0e22, 0xf986f341, + 0x0bd108e2, 0xf058fcd1, 0x110d0000, + }, { // 14.1 MHz + 0x00000002, 0xfff9fffa, 0x0021fffd, 0xffac0038, + 0x008eff4a, 0xff630184, 0x003afd8b, 0x00da0326, + 0xfd51fced, 0x050101c0, 0xf8cb0103, 0x0876fb10, + 0xf80a093e, 0x0543f338, 0xff7a0e66, 0xfa94f2b2, + 0x0b3f0967, 0xf081fc9b, 0x110d0000, + }, { // 14.2 MHz + 0x00000003, 0xfffbfff3, 0x001d0013, 0xffaa000b, + 0x00aaff89, 0xff13014a, 0x00cefd95, 0x000a037b, + 0xfe35fc1d, 0x044c0305, 0xf90cff7e, 0x08d5fc81, + 0xf7100834, 0x069ff3a7, 0xfe160e8d, 0xfbaaf231, + 0x0aa509e9, 0xf0adfc65, 0x110d0000, + }, { // 14.3 MHz + 0x00000003, 0xffffffef, 0x00140025, 0xffb4ffdd, + 0x00b2ffd6, 0xfedb00f0, 0x0150fdd3, 0xff380391, + 0xff36fb85, 0x035e0426, 0xf994fdfe, 0x08eefe0b, + 0xf6490702, 0x07e1f43e, 0xfcb60e97, 0xfcc6f1be, + 0x0a040a67, 0xf0dbfc30, 0x110d0000, + }, { // 14.4 MHz + 0x00000003, 0x0002ffee, 0x00070033, 0xffc9ffb4, + 0x00a40027, 0xfec3007e, 0x01b4fe3f, 0xfe760369, + 0x0044fb2e, 0x02450518, 0xfa5ffc90, 0x08c1ffa1, + 0xf5bc05ae, 0x0902f4fc, 0xfb600e85, 0xfde7f15a, + 0x095d0ae2, 0xf10cfbfb, 0x110d0000, + }, { // 14.5 MHz + 0xffff0002, 0x0005ffef, 0xfffa0038, 0xffe5ff95, + 0x00820074, 0xfecc0000, 0x01f0fed0, 0xfdd20304, + 0x014dfb1d, 0x010e05ce, 0xfb64fb41, 0x084e013b, + 0xf569043e, 0x0a00f5dd, 0xfa150e55, 0xff0bf104, + 0x08b00b59, 0xf13ffbc6, 0x110d0000, + }, { // 14.6 MHz + 0xffff0001, 0x0008fff4, 0xffed0035, 0x0005ff83, + 0x005000b4, 0xfef6ff82, 0x01ffff7a, 0xfd580269, + 0x0241fb53, 0xffca0640, 0xfc99fa1e, 0x079a02cb, + 0xf55502ba, 0x0ad5f6e0, 0xf8d90e0a, 0x0031f0bd, + 0x07fd0bcb, 0xf174fb91, 0x110d0000, + }, { // 14.7 MHz + 0xffffffff, 0x0009fffb, 0xffe4002a, 0x0025ff82, + 0x001400e0, 0xff3cff10, 0x01e10030, 0xfd1201a4, + 0x0311fbcd, 0xfe88066a, 0xfdf1f92f, 0x06aa0449, + 0xf57e0128, 0x0b7ef801, 0xf7b00da2, 0x0156f086, + 0x07450c39, 0xf1acfb5c, 0x110d0000, + }, { // 14.8 MHz + 0x0000fffe, 0x00080002, 0xffdf0019, 0x003fff92, + 0xffd600f1, 0xff96feb6, 0x019700e1, 0xfd0500c2, + 0x03b0fc84, 0xfd590649, 0xff5df87f, 0x058505aa, + 0xf5e4ff91, 0x0bf9f93c, 0xf69d0d20, 0x0279f05e, + 0x06880ca3, 0xf1e6fb28, 0x110d0000, + }, { // 14.9 MHz + 0x0000fffd, 0x00060009, 0xffdf0004, 0x0051ffb0, + 0xff9d00e8, 0xfffcfe7c, 0x01280180, 0xfd32ffd2, + 0x0413fd6e, 0xfc4d05df, 0x00d1f812, 0x043506e4, + 0xf685fdfb, 0x0c43fa8d, 0xf5a10c83, 0x0399f046, + 0x05c70d08, 0xf222faf3, 0x110d0000, + }, { // 15.0 MHz + 0x0000fffd, 0x0003000f, 0xffe5ffef, 0x0057ffd9, + 0xff7000c4, 0x0062fe68, 0x009e01ff, 0xfd95fee6, + 0x0435fe7d, 0xfb710530, 0x023cf7ee, 0x02c307ef, + 0xf75efc70, 0x0c5cfbef, 0xf4c10bce, 0x04b3f03f, + 0x05030d69, 0xf261fabf, 0x110d0000, + }, { // 15.1 MHz + 0x0000fffd, 0xffff0012, 0xffefffdc, 0x00510006, + 0xff540089, 0x00befe7c, 0x00060253, 0xfe27fe0d, + 0x0413ffa2, 0xfad10446, 0x0390f812, 0x013b08c3, + 0xf868faf6, 0x0c43fd5f, 0xf3fd0b02, 0x05c7f046, + 0x043b0dc4, 0xf2a1fa8b, 0x110d0000, + }, { // 15.2 MHz + 0x0001fffe, 0xfffc0012, 0xfffbffce, 0x003f0033, + 0xff4e003f, 0x0106feb6, 0xff6e0276, 0xfeddfd56, + 0x03b000cc, 0xfa740329, 0x04bff87f, 0xffaa095d, + 0xf99ef995, 0x0bf9fed8, 0xf3590a1f, 0x06d2f05e, + 0x03700e1b, 0xf2e4fa58, 0x110d0000, + }, { // 15.3 MHz + 0x0001ffff, 0xfff9000f, 0x0009ffc8, 0x00250059, + 0xff5effee, 0x0132ff10, 0xfee30265, 0xffaafccf, + 0x031101eb, 0xfa6001e8, 0x05bdf92f, 0xfe1b09b6, + 0xfafaf852, 0x0b7e0055, 0xf2d50929, 0x07d3f086, + 0x02a30e6c, 0xf329fa24, 0x110d0000, + }, { // 15.4 MHz + 0x00010001, 0xfff80009, 0x0015ffca, 0x00050074, + 0xff81ff9f, 0x013dff82, 0xfe710221, 0x007cfc80, + 0x024102ed, 0xfa940090, 0x0680fa1e, 0xfc9b09cd, + 0xfc73f736, 0x0ad501d0, 0xf2740820, 0x08c9f0bd, + 0x01d40eb9, 0xf371f9f1, 0x110d0000, + }, { // 15.5 MHz + 0x00000002, 0xfff80002, 0x001effd5, 0xffe5007f, + 0xffb4ff5b, 0x01280000, 0xfe2401b0, 0x0146fc70, + 0x014d03c6, 0xfb10ff32, 0x0701fb41, 0xfb3709a1, + 0xfe00f644, 0x0a000345, 0xf2350708, 0x09b2f104, + 0x01050eff, 0xf3baf9be, 0x110d0000, + }, { // 15.6 MHz + 0x00000003, 0xfff9fffb, 0x0022ffe6, 0xffc9007a, + 0xfff0ff29, 0x00f2007e, 0xfe01011b, 0x01f6fc9e, + 0x00440467, 0xfbccfdde, 0x0738fc90, 0xf9f70934, + 0xff99f582, 0x090204b0, 0xf21a05e1, 0x0a8df15a, + 0x00340f41, 0xf405f98b, 0x110d0000, + }, { // 15.7 MHz + 0x00000003, 0xfffcfff4, 0x0020fffa, 0xffb40064, + 0x002fff11, 0x00a400f0, 0xfe0d006e, 0x0281fd09, + 0xff3604c9, 0xfcbffca2, 0x0726fdfe, 0xf8e80888, + 0x0134f4f3, 0x07e1060c, 0xf22304af, 0x0b59f1be, + 0xff640f7d, 0xf452f959, 0x110d0000, + }, { // 15.8 MHz + 0x00000003, 0x0000fff0, 0x001a0010, 0xffaa0041, + 0x0067ff13, 0x0043014a, 0xfe46ffb9, 0x02dbfda8, + 0xfe3504e5, 0xfddcfb8d, 0x06c9ff7e, 0xf81107a2, + 0x02c9f49a, 0x069f0753, 0xf2500373, 0x0c14f231, + 0xfe930fb3, 0xf4a1f927, 0x110d0000, + }, { // 15.9 MHz + 0xffff0002, 0x0003ffee, 0x000f0023, 0xffac0016, + 0x0093ff31, 0xffdc0184, 0xfea6ff09, 0x02fdfe70, + 0xfd5104ba, 0xff15faac, 0x06270103, 0xf7780688, + 0x044df479, 0x05430883, 0xf2a00231, 0x0cbef2b2, + 0xfdc40fe3, 0xf4f2f8f5, 0x110d0000, + }, { // 16.0 MHz + 0xffff0001, 0x0006ffef, 0x00020031, 0xffbaffe8, + 0x00adff66, 0xff790198, 0xff26fe6e, 0x02e5ff55, + 0xfc99044a, 0x005bfa09, 0x0545027f, 0xf7230541, + 0x05b8f490, 0x03d20997, 0xf31300eb, 0x0d55f341, + 0xfcf6100e, 0xf544f8c3, 0x110d0000, + } +}; + static void cx23885_dif_setup(struct i2c_client *client, u32 ifHz) { u64 pll_freq; u32 pll_freq_word; + const u32 *coeffs; v4l_dbg(1, cx25840_debug, client, "%s(%d)\n", __func__, ifHz); @@ -2763,2889 +3554,26 @@ static void cx23885_dif_setup(struct i2c_client *client, u32 ifHz) v4l_dbg(1, cx25840_debug, client, "%s(%d) again\n", __func__, ifHz); - switch (ifHz) { - case 3000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00080012); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0024); - cx25840_write4(client, DIF_BPF_COEFF67, 0x001bfff8); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffb4ff50); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed8fe68); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe24fe34); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfebaffc7); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d031f); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x04f0065d); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x07010688); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x04c901d6); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe00f9d3); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f342); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf235f337); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf64efb22); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0105070f); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x0c460fce); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 3100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00070012); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00220032); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00370026); - cx25840_write4(client, DIF_BPF_COEFF89, 0xfff0ff91); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff0efe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01fdcc); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe0afedb); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440224); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0434060c); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0738074e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x06090361); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xff99fb39); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef3b6); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21af2a5); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf573fa33); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0034067d); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x0bfb0fb9); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 3200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000000); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0004000e); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00200038); - cx25840_write4(client, DIF_BPF_COEFF67, 0x004c004f); - cx25840_write4(client, DIF_BPF_COEFF89, 0x002fffdf); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff5cfeb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0dfd92); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd7ffe03); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36010a); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x03410575); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x072607d2); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x071804d5); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0134fcb7); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff451); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf223f22e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4a7f94b); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xff6405e8); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x0bae0fa4); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 3300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00000008); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001a0036); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0056006d); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00670030); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffbdff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe46fd8d); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd25fd4f); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35ffe0); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0224049f); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c9080e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x07ef0627); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c9fe45); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f513); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf250f1d2); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3ecf869); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe930552); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x0b5f0f8f); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 3400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd0001); - cx25840_write4(client, DIF_BPF_COEFF45, 0x000f002c); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0054007d); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0093007c); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0024ff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea6fdbb); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd03fcca); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51feb9); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x00eb0392); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x06270802); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08880750); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x044dffdb); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf5f8); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a0f193); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf342f78f); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc404b9); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x0b0e0f78); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 3500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff9); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0002001b); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0046007d); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00ad00ba); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00870000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff26fe1a); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd1bfc7e); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fda4); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xffa5025c); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x054507ad); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08dd0847); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b80172); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef6ff); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf313f170); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2abf6bd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6041f); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x0abc0f61); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 3600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff3); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff50006); - cx25840_write4(client, DIF_BPF_COEFF67, 0x002f006c); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00b200e3); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00dc007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xffb9fea0); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd6bfc71); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fcb1); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe65010b); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x042d0713); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08ec0906); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x07020302); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff823); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3a7f16a); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf228f5f5); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfc2a0384); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x0a670f4a); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 3700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7ffef); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe9fff1); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0010004d); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00a100f2); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x011a00f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0053ff44); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdedfca2); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fbef); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd39ffae); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x02ea0638); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08b50987); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x08230483); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f960); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf45bf180); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1b8f537); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfb6102e7); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x0a110f32); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 3800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9ffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffdd); - cx25840_write4(client, DIF_BPF_COEFF67, 0xfff00024); - cx25840_write4(client, DIF_BPF_COEFF89, 0x007c00e5); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x013a014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x00e6fff8); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe98fd0f); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fb67); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc32fe54); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x01880525); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x083909c7); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x091505ee); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7fab3); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf52df1b4); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf15df484); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfa9b0249); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x09ba0f19); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 3900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000000); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbfff0); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffcf); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1fff6); - cx25840_write4(client, DIF_BPF_COEFF89, 0x004800be); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x01390184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x016300ac); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xff5efdb1); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fb23); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb5cfd0d); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x001703e4); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x077b09c4); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x09d2073c); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251fc18); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf61cf203); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf118f3dc); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf9d801aa); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x09600eff); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 4000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffefff4); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffc8); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffca); - cx25840_write4(client, DIF_BPF_COEFF89, 0x000b0082); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x01170198); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01c10152); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0030fe7b); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fb24); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfac3fbe9); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfea5027f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x0683097f); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a560867); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2fd89); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf723f26f); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0e8f341); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf919010a); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x09060ee5); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 4100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0002fffb); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe8ffca); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffa4); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffcd0036); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d70184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f601dc); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x00ffff60); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb6d); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa6efaf5); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd410103); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x055708f9); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a9e0969); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543ff02); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf842f2f5); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0cef2b2); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf85e006b); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x08aa0ecb); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 4200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00050003); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff3ffd3); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaff8b); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff95ffe5); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0080014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fe023f); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x01ba0050); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fbf8); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa62fa3b); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbf9ff7e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x04010836); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aa90a3d); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f007f); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf975f395); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0cbf231); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf7a9ffcb); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x084c0eaf); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 4300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000a); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0000ffe4); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ff81); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff6aff96); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x001c00f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01d70271); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0254013b); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fcbd); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa9ff9c5); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfadbfdfe); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x028c073b); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a750adf); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e101fa); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfab8f44e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0ddf1be); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf6f9ff2b); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x07ed0e94); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 4400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0009000f); - cx25840_write4(client, DIF_BPF_COEFF45, 0x000efff8); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ff87); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff52ff54); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffb5007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01860270); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c00210); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fdb2); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb22f997); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9f2fc90); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x0102060f); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a050b4c); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902036e); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfc0af51e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf106f15a); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf64efe8b); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x078d0e77); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 4500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00080012); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0019000e); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff9e); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff4fff25); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff560000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0112023b); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f702c0); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfec8); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbe5f9b3); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf947fb41); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xff7004b9); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x095a0b81); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a0004d8); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfd65f603); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf144f104); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf5aafdec); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x072b0e5a); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 4600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00060012); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00200022); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ffc1); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff61ff10); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff09ff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x008601d7); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f50340); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fff0); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcddfa19); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8e2fa1e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfde30343); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x08790b7f); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50631); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfec7f6fc); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf198f0bd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf50dfd4e); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x06c90e3d); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 4700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0003000f); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00220030); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ffed); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff87ff15); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed6ff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xffed014c); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b90386); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110119); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfdfefac4); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8c6f92f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc6701b7); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x07670b44); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0776); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x002df807); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf200f086); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf477fcb1); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x06650e1e); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 4800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0009); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0038); - cx25840_write4(client, DIF_BPF_COEFF67, 0x003f001b); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffbcff36); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec2feb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff5600a5); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0248038d); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00232); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xff39fbab); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8f4f87f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb060020); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x062a0ad2); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf908a3); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0192f922); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf27df05e); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf3e8fc14); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x06000e00); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 4900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc0002); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00160037); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00510046); - cx25840_write4(client, DIF_BPF_COEFF89, 0xfff9ff6d); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed0fe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfecefff0); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x01aa0356); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413032b); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x007ffcc5); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf96cf812); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9cefe87); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x04c90a2c); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c4309b4); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x02f3fa4a); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf30ef046); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf361fb7a); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x059b0de0); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 5000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffa); - cx25840_write4(client, DIF_BPF_COEFF45, 0x000a002d); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00570067); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0037ffb5); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfefffe68); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe62ff3d); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x00ec02e3); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x043503f6); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x01befe05); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa27f7ee); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8c6fcf8); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x034c0954); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5c0aa4); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x044cfb7e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3b1f03f); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf2e2fae1); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x05340dc0); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 5100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff4); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfffd001e); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0051007b); - cx25840_write4(client, DIF_BPF_COEFF89, 0x006e0006); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff48fe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe1bfe9a); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x001d023e); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130488); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x02e6ff5b); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb1ef812); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7f7fb7f); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x01bc084e); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c430b72); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x059afcba); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf467f046); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf26cfa4a); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x04cd0da0); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 5200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8ffef); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff00009); - cx25840_write4(client, DIF_BPF_COEFF67, 0x003f007f); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00980056); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffa5feb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe00fe15); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xff4b0170); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b004d7); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x03e800b9); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc48f87f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf768fa23); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0022071f); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf90c1b); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x06dafdfd); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf52df05e); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf1fef9b5); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x04640d7f); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 5300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9ffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe6fff3); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00250072); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00af009c); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x000cff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe13fdb8); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe870089); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x031104e1); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x04b8020f); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd98f92f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf71df8f0); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe8805ce); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0c9c); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0808ff44); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf603f086); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf19af922); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x03fb0d5e); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 5400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcffef); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffe0); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00050056); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00b000d1); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0071ff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe53fd8c); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfddfff99); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104a3); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x054a034d); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xff01fa1e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf717f7ed); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfcf50461); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50cf4); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0921008d); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf6e7f0bd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf13ff891); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x03920d3b); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 5500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffffff3); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffd1); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5002f); - cx25840_write4(client, DIF_BPF_COEFF89, 0x009c00ed); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00cb0000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfebafd94); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd61feb0); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d0422); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x05970464); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0074fb41); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf759f721); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfb7502de); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000d21); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a2201d4); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf7d9f104); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0edf804); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x03280d19); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 5600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0003fffa); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe3ffc9); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffc90002); - cx25840_write4(client, DIF_BPF_COEFF89, 0x007500ef); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x010e007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff3dfdcf); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd16fddd); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440365); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x059b0548); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x01e3fc90); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7dff691); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa0f014d); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x09020d23); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b0a0318); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf8d7f15a); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0a5f779); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x02bd0cf6); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 5700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00060001); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffecffc9); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ffd4); - cx25840_write4(client, DIF_BPF_COEFF89, 0x004000d5); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x013600f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xffd3fe39); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd04fd31); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff360277); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x055605ef); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x033efdfe); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8a5f642); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf8cbffb6); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e10cfb); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0bd50456); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf9dff1be); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf067f6f2); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x02520cd2); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 5800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00080009); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff8ffd2); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaffac); - cx25840_write4(client, DIF_BPF_COEFF89, 0x000200a3); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x013c014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x006dfec9); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd2bfcb7); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe350165); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x04cb0651); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0477ff7e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9a5f635); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7b1fe20); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0ca8); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c81058b); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfaf0f231); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf033f66d); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x01e60cae); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 5900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0009000e); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0005ffe1); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffacff90); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffc5005f); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x01210184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x00fcff72); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd8afc77); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51003f); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x04020669); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x05830103); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfad7f66b); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6c8fc93); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430c2b); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d0d06b5); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfc08f2b2); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf00af5ec); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x017b0c89); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 6000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00070012); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0012fff5); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaff82); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff8e000f); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e80198); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01750028); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe18fc75); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99ff15); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x03050636); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0656027f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc32f6e2); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf614fb17); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20b87); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d7707d2); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfd26f341); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xefeaf56f); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x010f0c64); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 6100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00050012); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001c000b); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1ff84); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff66ffbe); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00960184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01cd00da); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfeccfcb2); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fdf9); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x01e005bc); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x06e703e4); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfdabf798); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf599f9b3); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x02510abd); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dbf08df); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfe48f3dc); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xefd5f4f6); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x00a20c3e); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 6200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0002000f); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0021001f); - cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0ff97); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff50ff74); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0034014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fa0179); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xff97fd2a); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fcfa); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x00a304fe); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x07310525); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xff37f886); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55cf86e); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c709d0); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de209db); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xff6df484); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xefcbf481); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x00360c18); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 6300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffe000a); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0021002f); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0010ffb8); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff50ff3b); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffcc00f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fa01fa); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0069fdd4); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fc26); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xff5d0407); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x07310638); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x00c9f9a8); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55cf74e); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xff3908c3); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de20ac3); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0093f537); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xefcbf410); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xffca0bf2); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 6400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffb0003); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001c0037); - cx25840_write4(client, DIF_BPF_COEFF67, 0x002fffe2); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff66ff17); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff6a007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01cd0251); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0134fea5); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fb8b); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe2002e0); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x06e70713); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x0255faf5); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf599f658); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaf0799); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dbf0b96); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x01b8f5f5); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xefd5f3a3); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xff5e0bca); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 6500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffb); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00120037); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00460010); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff8eff0f); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff180000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01750276); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x01e8ff8d); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fb31); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcfb0198); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x065607ad); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x03cefc64); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf614f592); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2e0656); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d770c52); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x02daf6bd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xefeaf33b); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfef10ba3); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 6600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7fff5); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0005002f); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0054003c); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffc5ff22); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedfff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x00fc0267); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0276007e); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb1c); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbfe003e); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x05830802); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x0529fdec); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6c8f4fe); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabd04ff); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d0d0cf6); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x03f8f78f); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf00af2d7); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfe850b7b); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 6700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff0); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff80020); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00560060); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0002ff4e); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec4ff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x006d0225); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02d50166); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb4e); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb35fee1); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0477080e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x065bff82); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7b1f4a0); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf9610397); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c810d80); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0510f869); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf033f278); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfe1a0b52); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 6800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffaffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffec000c); - cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0078); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0040ff8e); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecafeb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xffd301b6); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fc0235); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fbc5); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaaafd90); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x033e07d2); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x075b011b); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf8cbf47a); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81f0224); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0bd50def); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0621f94b); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf067f21e); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfdae0b29); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 6900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffdffef); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe3fff6); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0037007f); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0075ffdc); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef2fe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff3d0122); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02ea02dd); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fc79); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa65fc5d); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x01e3074e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x082102ad); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa0ff48c); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fe00a9); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b0a0e43); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0729fa33); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0a5f1c9); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfd430b00); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 7000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0001fff3); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffe2); - cx25840_write4(client, DIF_BPF_COEFF67, 0x001b0076); - cx25840_write4(client, DIF_BPF_COEFF89, 0x009c002d); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff35fe68); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfeba0076); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x029f0352); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfd60); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa69fb53); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x00740688); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08a7042d); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfb75f4d6); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600ff2d); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a220e7a); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0827fb22); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0edf17a); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfcd80ad6); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 7100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0004fff9); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffd2); - cx25840_write4(client, DIF_BPF_COEFF67, 0xfffb005e); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00b0007a); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff8ffe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe53ffc1); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0221038c); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fe6e); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfab6fa80); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xff010587); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08e90590); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfcf5f556); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bfdb3); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x09210e95); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0919fc15); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf13ff12f); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfc6e0aab); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 7200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00070000); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe6ffc9); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffdb0039); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00af00b8); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfff4feb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe13ff10); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x01790388); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311ff92); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb48f9ed); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd980453); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08e306cd); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe88f60a); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482fc40); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x08080e93); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x09fdfd0c); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf19af0ea); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfc050a81); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 7300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00080008); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff0ffc9); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1000d); - cx25840_write4(client, DIF_BPF_COEFF89, 0x009800e2); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x005bff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe00fe74); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x00b50345); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b000bc); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc18f9a1); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc4802f9); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x089807dc); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0022f6f0); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407fada); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x06da0e74); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ad3fe06); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf1fef0ab); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfb9c0a55); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 7400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000e); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfffdffd0); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffafffdf); - cx25840_write4(client, DIF_BPF_COEFF89, 0x006e00f2); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00b8ff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe1bfdf8); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xffe302c8); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x041301dc); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd1af99e); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb1e0183); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x080908b5); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x01bcf801); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdf985); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x059a0e38); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b99ff03); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf26cf071); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfb330a2a); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 7500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00070011); - cx25840_write4(client, DIF_BPF_COEFF45, 0x000affdf); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffa9ffb5); - cx25840_write4(client, DIF_BPF_COEFF89, 0x003700e6); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x01010000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe62fda8); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xff140219); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x043502e1); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe42f9e6); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa270000); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x073a0953); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x034cf939); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3a4f845); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x044c0de1); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c4f0000); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf2e2f03c); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfacc09fe); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 7600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00040012); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0016fff3); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffafff95); - cx25840_write4(client, DIF_BPF_COEFF89, 0xfff900c0); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0130007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfecefd89); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe560146); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x041303bc); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xff81fa76); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf96cfe7d); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x063209b1); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x04c9fa93); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdf71e); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x02f30d6e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cf200fd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf361f00e); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfa6509d1); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 7700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00010010); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0008); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1ff84); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffbc0084); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x013e00f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff56fd9f); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdb8005c); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00460); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x00c7fb45); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8f4fd07); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x04fa09ce); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x062afc07); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407f614); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x01920ce0); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d8301fa); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf3e8efe5); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfa0009a4); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 7800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd000b); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0022001d); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffdbff82); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff870039); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x012a014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xffedfde7); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd47ff6b); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x031104c6); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0202fc4c); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8c6fbad); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x039909a7); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0767fd8e); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482f52b); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x002d0c39); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e0002f4); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf477efc2); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf99b0977); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 7900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa0004); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0020002d); - cx25840_write4(client, DIF_BPF_COEFF67, 0xfffbff91); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff61ffe8); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f70184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0086fe5c); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd0bfe85); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104e5); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0323fd7d); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8e2fa79); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x021d093f); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0879ff22); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bf465); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfec70b79); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e6803eb); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf50defa5); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf937094a); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 8000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fffd); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00190036); - cx25840_write4(client, DIF_BPF_COEFF67, 0x001bffaf); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff4fff99); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00aa0198); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0112fef3); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd09fdb9); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d04be); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x041bfecc); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf947f978); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x00900897); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x095a00b9); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f3c5); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfd650aa3); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ebc04de); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf5aaef8e); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf8d5091c); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 8100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7fff6); - cx25840_write4(client, DIF_BPF_COEFF45, 0x000e0038); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0037ffd7); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff52ff56); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x004b0184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0186ffa1); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd40fd16); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440452); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x04de0029); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9f2f8b2); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfefe07b5); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a05024d); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef34d); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfc0a09b8); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0efa05cd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf64eef7d); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf87308ed); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 8200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff0); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00000031); - cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0005); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff6aff27); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffe4014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01d70057); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdacfca6); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3603a7); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x05610184); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfadbf82e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd74069f); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a7503d6); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff2ff); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfab808b9); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f2306b5); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf6f9ef72); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf81308bf); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 8300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff30022); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00560032); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff95ff10); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff8000f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fe0106); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe46fc71); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3502c7); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x059e02ce); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbf9f7f2); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfbff055b); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aa9054c); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f2db); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf97507aa); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f350797); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf7a9ef6d); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf7b40890); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 8400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffeffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe8000f); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00540058); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffcdff14); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff29007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f6019e); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xff01fc7c); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd5101bf); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x059203f6); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd41f7fe); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfaa903f3); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a9e06a9); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf2e2); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf842068b); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f320871); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf85eef6e); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf7560860); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 8500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0002fff2); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1fff9); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00460073); - cx25840_write4(client, DIF_BPF_COEFF89, 0x000bff34); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfee90000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01c10215); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xffd0fcc5); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99009d); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x053d04f1); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfea5f853); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf97d0270); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a5607e4); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef314); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf723055f); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f180943); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf919ef75); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf6fa0830); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 8600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0005fff8); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffe4); - cx25840_write4(client, DIF_BPF_COEFF67, 0x002f007f); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0048ff6b); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec7ff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0163025f); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x00a2fd47); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17ff73); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x04a405b2); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0017f8ed); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf88500dc); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x09d208f9); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff370); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf61c0429); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ee80a0b); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf9d8ef82); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf6a00800); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 8700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0007ffff); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffd4); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0010007a); - cx25840_write4(client, DIF_BPF_COEFF89, 0x007cffb2); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec6ff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x00e60277); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0168fdf9); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fe50); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x03ce0631); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0188f9c8); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7c7ff43); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x091509e3); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f3f6); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf52d02ea); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ea30ac9); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfa9bef95); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf64607d0); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 8800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00090007); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe9ffca); - cx25840_write4(client, DIF_BPF_COEFF67, 0xfff00065); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00a10003); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfee6feb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0053025b); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0213fed0); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fd46); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x02c70668); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x02eafadb); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf74bfdae); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x08230a9c); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7f4a3); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf45b01a6); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e480b7c); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfb61efae); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf5ef079f); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 8900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000d); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff5ffc8); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffd10043); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00b20053); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff24fe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xffb9020c); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0295ffbb); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fc64); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x019b0654); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x042dfc1c); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf714fc2a); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x07020b21); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251f575); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3a7005e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0dd80c24); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfc2aefcd); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf599076e); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 9000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00060011); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0002ffcf); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffba0018); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00ad009a); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff79fe68); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff260192); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02e500ab); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fbb6); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x005b05f7); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0545fd81); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf723fabf); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b80b70); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2f669); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf313ff15); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d550cbf); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6eff2); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf544073d); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 9100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00030012); - cx25840_write4(client, DIF_BPF_COEFF45, 0x000fffdd); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffea); - cx25840_write4(client, DIF_BPF_COEFF89, 0x009300cf); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffdcfe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea600f7); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fd0190); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb46); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xff150554); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0627fefd); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf778f978); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x044d0b87); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543f77d); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a0fdcf); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cbe0d4e); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc4f01d); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4f2070b); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 9200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00000010); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001afff0); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaffbf); - cx25840_write4(client, DIF_BPF_COEFF89, 0x006700ed); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0043feb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe460047); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02db0258); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb1b); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfddc0473); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c90082); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf811f85e); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c90b66); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x069ff8ad); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf250fc8d); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c140dcf); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe93f04d); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4a106d9); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 9300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc000c); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00200006); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ff9c); - cx25840_write4(client, DIF_BPF_COEFF89, 0x002f00ef); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00a4ff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0dff92); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x028102f7); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb37); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcbf035e); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x07260202); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8e8f778); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x01340b0d); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1f9f4); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf223fb51); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b590e42); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xff64f083); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf45206a7); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 9400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff90005); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0022001a); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ff86); - cx25840_write4(client, DIF_BPF_COEFF89, 0xfff000d7); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f2ff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01fee5); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x01f60362); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb99); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbcc0222); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x07380370); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9f7f6cc); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xff990a7e); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902fb50); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21afa1f); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0a8d0ea6); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0034f0bf); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4050675); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 9500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fffe); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001e002b); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff81); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffb400a5); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x01280000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe24fe50); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x01460390); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfc3a); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb1000ce); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x070104bf); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb37f65f); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe0009bc); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a00fcbb); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf235f8f8); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x09b20efc); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0105f101); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf3ba0642); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 9600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff7); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00150036); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ff8c); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff810061); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x013d007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe71fddf); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x007c0380); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fd13); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa94ff70); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x068005e2); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc9bf633); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfc7308ca); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad5fe30); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf274f7e0); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x08c90f43); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x01d4f147); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf371060f); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 9700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fff1); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00090038); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ffa7); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff5e0012); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x013200f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfee3fd9b); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xffaa0331); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fe15); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa60fe18); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x05bd06d1); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe1bf64a); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfafa07ae); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7effab); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2d5f6d7); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x07d30f7a); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x02a3f194); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf32905dc); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 9800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfffb0032); - cx25840_write4(client, DIF_BPF_COEFF67, 0x003fffcd); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff4effc1); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0106014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff6efd8a); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfedd02aa); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0ff34); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa74fcd7); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x04bf0781); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xffaaf6a3); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf99e066b); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf90128); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf359f5e1); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x06d20fa2); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0370f1e5); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2e405a8); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 9900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0xffffffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffef0024); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0051fffa); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff54ff77); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00be0184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0006fdad); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe2701f3); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413005e); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfad1fbba); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x039007ee); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x013bf73d); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf868050a); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c4302a1); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3fdf4fe); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x05c70fba); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x043bf23c); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2a10575); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 10000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0003fff1); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe50011); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00570027); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff70ff3c); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00620198); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x009efe01); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd95011a); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x04350183); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb71fad0); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x023c0812); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x02c3f811); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf75e0390); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5c0411); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf4c1f432); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x04b30fc1); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0503f297); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2610541); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 10100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0006fff7); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffdffffc); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00510050); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff9dff18); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfffc0184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0128fe80); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd32002e); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130292); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc4dfa21); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x00d107ee); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x0435f91c); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6850205); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c430573); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf5a1f37d); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x03990fba); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x05c7f2f8); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf222050d); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 10200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffe); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffdfffe7); - cx25840_write4(client, DIF_BPF_COEFF67, 0x003f006e); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffd6ff0f); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff96014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0197ff1f); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd05ff3e); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0037c); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd59f9b7); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xff5d0781); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x0585fa56); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5e4006f); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf906c4); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf69df2e0); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x02790fa2); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0688f35d); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1e604d8); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 10300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00090005); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe4ffd6); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0025007e); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0014ff20); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff3c00f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e1ffd0); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd12fe5c); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110433); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe88f996); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfdf106d1); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x06aafbb7); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf57efed8); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e07ff); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf7b0f25e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x01560f7a); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0745f3c7); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1ac04a4); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 10400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000c); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffedffcb); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0005007d); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0050ff4c); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef6007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01ff0086); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd58fd97); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104ad); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xffcaf9c0); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc9905e2); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x079afd35); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf555fd46); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50920); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf8d9f1f6); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x00310f43); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x07fdf435); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf174046f); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 10500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00050011); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfffaffc8); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5006b); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0082ff8c); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecc0000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f00130); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdd2fcfc); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d04e3); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x010efa32); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb6404bf); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x084efec5); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf569fbc2); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000a23); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfa15f1ab); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xff0b0efc); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x08b0f4a7); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf13f043a); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 10600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00020012); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0007ffcd); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9004c); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00a4ffd9); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec3ff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01b401c1); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe76fc97); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x004404d2); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0245fae8); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa5f0370); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08c1005f); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5bcfa52); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x09020b04); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfb60f17b); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfde70ea6); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x095df51e); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf10c0405); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 10700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0011); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0014ffdb); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffb40023); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00b2002a); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedbff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0150022d); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xff38fc6f); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36047b); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x035efbda); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9940202); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08ee01f5); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf649f8fe); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e10bc2); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfcb6f169); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfcc60e42); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0a04f599); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0db03d0); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 10800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffb000d); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001dffed); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffaafff5); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00aa0077); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff13feb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x00ce026b); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x000afc85); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3503e3); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x044cfcfb); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf90c0082); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08d5037f); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf710f7cc); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0c59); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfe16f173); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfbaa0dcf); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0aa5f617); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0ad039b); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 10900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff90006); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00210003); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffc8); - cx25840_write4(client, DIF_BPF_COEFF89, 0x008e00b6); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff63fe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x003a0275); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x00dafcda); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd510313); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0501fe40); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8cbfefd); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x087604f0); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf80af6c2); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430cc8); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xff7af19a); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfa940d4e); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0b3ff699); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0810365); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 11000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8ffff); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00210018); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffa3); - cx25840_write4(client, DIF_BPF_COEFF89, 0x006000e1); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffc4fe68); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xffa0024b); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x019afd66); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc990216); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0575ff99); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8d4fd81); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x07d40640); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf932f5e6); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20d0d); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x00dff1de); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf9860cbf); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0bd1f71e); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf058032f); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 11100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff8); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001b0029); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1ff8a); - cx25840_write4(client, DIF_BPF_COEFF89, 0x002600f2); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x002cfe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff0f01f0); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x023bfe20); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc1700fa); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x05a200f7); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf927fc1c); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x06f40765); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa82f53b); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x02510d27); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0243f23d); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf8810c24); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0c5cf7a7); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf03102fa); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 11200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff2); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00110035); - cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0ff81); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffe700e7); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x008ffeb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe94016d); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b0fefb); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3ffd1); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x05850249); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9c1fadb); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x05de0858); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfbf2f4c4); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c70d17); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x03a0f2b8); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf7870b7c); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0cdff833); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf00d02c4); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 11300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffdffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00040038); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0010ff88); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffac00c2); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e2ff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe3900cb); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f1ffe9); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3feaa); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x05210381); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa9cf9c8); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x04990912); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfd7af484); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xff390cdb); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x04f4f34d); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf69a0ac9); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0d5af8c1); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xefec028e); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 11400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0000ffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff60033); - cx25840_write4(client, DIF_BPF_COEFF67, 0x002fff9f); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff7b0087); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x011eff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe080018); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f900d8); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fd96); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x04790490); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbadf8ed); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x032f098e); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xff10f47d); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaf0c75); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x063cf3fc); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf5ba0a0b); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0dccf952); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xefcd0258); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 11500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0004fff1); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffea0026); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0046ffc3); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff5a003c); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x013b0000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe04ff63); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c801b8); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fca6); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0397056a); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfcecf853); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x01ad09c9); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x00acf4ad); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2e0be7); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0773f4c2); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4e90943); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e35f9e6); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xefb10221); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 11600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0007fff6); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe20014); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0054ffee); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff4effeb); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0137007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2efebb); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0260027a); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fbe6); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x02870605); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfe4af7fe); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x001d09c1); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0243f515); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabd0b32); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0897f59e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4280871); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e95fa7c); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef9701eb); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 11700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffd); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffff); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0056001d); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff57ff9c); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x011300f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe82fe2e); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x01ca0310); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb62); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0155065a); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xffbaf7f2); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe8c0977); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x03cef5b2); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf9610a58); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x09a5f68f); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3790797); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0eebfb14); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef8001b5); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 11800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00080004); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffe9); - cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0047); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff75ff58); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d1014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfef9fdc8); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0111036f); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb21); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x00120665); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x012df82e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd0708ec); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0542f682); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81f095c); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a9af792); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2db06b5); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f38fbad); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef6c017e); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 11900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0007000b); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe7ffd8); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00370068); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffa4ff28); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00790184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff87fd91); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x00430392); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb26); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfece0626); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0294f8b2); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb990825); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0698f77f); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fe0842); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b73f8a7); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf25105cd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f7bfc48); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef5a0148); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 12000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00050010); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff2ffcc); - cx25840_write4(client, DIF_BPF_COEFF67, 0x001b007b); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffdfff10); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00140198); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0020fd8e); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xff710375); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfb73); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd9a059f); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x03e0f978); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfa4e0726); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x07c8f8a7); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600070c); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c2ff9c9); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1db04de); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fb4fce5); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef4b0111); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 12100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00010012); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffffffc8); - cx25840_write4(client, DIF_BPF_COEFF67, 0xfffb007e); - cx25840_write4(client, DIF_BPF_COEFF89, 0x001dff14); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffad0184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x00b7fdbe); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfea9031b); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fc01); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc8504d6); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0504fa79); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf93005f6); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x08caf9f2); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52b05c0); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0ccbfaf9); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf17903eb); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fe3fd83); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3f00db); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 12200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffe0011); - cx25840_write4(client, DIF_BPF_COEFF45, 0x000cffcc); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffdb0071); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0058ff32); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff4f014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x013cfe1f); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdfb028a); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fcc9); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb9d03d6); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x05f4fbad); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf848049d); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0999fb5b); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf4820461); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d46fc32); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf12d02f4); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x1007fe21); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3600a4); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 12300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa000e); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0017ffd9); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffc10055); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0088ff68); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff0400f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01a6fea7); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd7501cc); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0fdc0); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaef02a8); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x06a7fd07); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf79d0326); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a31fcda); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf40702f3); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d9ffd72); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0f601fa); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x1021fec0); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2f006d); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 12400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80007); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001fffeb); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffaf002d); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00a8ffb0); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed3007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e9ff4c); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd2000ee); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413fed8); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa82015c); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0715fe7d); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7340198); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a8dfe69); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bd017c); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dd5feb8); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0d500fd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x1031ff60); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2b0037); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 12500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff70000); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00220000); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffa90000); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00b30000); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec20000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x02000000); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd030000); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x04350000); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa5e0000); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x073b0000); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7110000); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aac0000); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3a40000); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de70000); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0c90000); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x10360000); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef290000); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 12600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff9); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001f0015); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffafffd3); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00a80050); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed3ff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e900b4); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd20ff12); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130128); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa82fea4); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x07150183); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf734fe68); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a8d0197); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdfe84); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dd50148); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0d5ff03); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x103100a0); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2bffc9); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 12700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff2); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00170027); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1ffab); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00880098); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff04ff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01a60159); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd75fe34); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00240); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaeffd58); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x06a702f9); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf79dfcda); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a310326); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407fd0d); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d9f028e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0f6fe06); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x10210140); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2fff93); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 12800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffeffef); - cx25840_write4(client, DIF_BPF_COEFF45, 0x000c0034); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffdbff8f); - cx25840_write4(client, DIF_BPF_COEFF89, 0x005800ce); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff4ffeb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x013c01e1); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdfbfd76); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110337); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb9dfc2a); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x05f40453); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf848fb63); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x099904a5); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482fb9f); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d4603ce); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf12dfd0c); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x100701df); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef36ff5c); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 12900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0001ffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffff0038); - cx25840_write4(client, DIF_BPF_COEFF67, 0xfffbff82); - cx25840_write4(client, DIF_BPF_COEFF89, 0x001d00ec); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffadfe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x00b70242); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfea9fce5); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x024103ff); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc85fb2a); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x05040587); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf930fa0a); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x08ca060e); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bfa40); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0ccb0507); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf179fc15); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fe3027d); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3fff25); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 13000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0005fff0); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff20034); - cx25840_write4(client, DIF_BPF_COEFF67, 0x001bff85); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffdf00f0); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0014fe68); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x00200272); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xff71fc8b); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d048d); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd9afa61); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x03e00688); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfa4ef8da); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x07c80759); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f8f4); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c2f0637); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1dbfb22); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fb4031b); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef4bfeef); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 13100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0007fff5); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe70028); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0037ff98); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffa400d8); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0079fe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff87026f); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0043fc6e); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x004404da); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfecef9da); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0294074e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb99f7db); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x06980881); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef7be); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b730759); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf251fa33); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f7b03b8); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef5afeb8); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 13200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffc); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe00017); - cx25840_write4(client, DIF_BPF_COEFF67, 0x004cffb9); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff7500a8); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d1feb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfef90238); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0111fc91); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3604df); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0012f99b); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x012d07d2); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd07f714); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0542097e); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff6a4); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a9a086e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2dbf94b); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f380453); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef6cfe82); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 13300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00080003); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffde0001); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0056ffe3); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff570064); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0113ff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe8201d2); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x01cafcf0); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35049e); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0155f9a6); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xffba080e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe8cf689); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x03ce0a4e); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f5a8); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x09a50971); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf379f869); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0eeb04ec); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef80fe4b); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 13400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0007000a); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe2ffec); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00540012); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff4e0015); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0137ff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2e0145); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0260fd86); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51041a); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0287f9fb); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfe4a0802); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x001df63f); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x02430aeb); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf4ce); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x08970a62); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf428f78f); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e950584); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef97fe15); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 13500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0004000f); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffeaffda); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0046003d); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff5affc4); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x013b0000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe04009d); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c8fe48); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99035a); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0397fa96); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfcec07ad); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x01adf637); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x00ac0b53); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef419); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x07730b3e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4e9f6bd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e35061a); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xefb1fddf); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 13600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00000012); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff6ffcd); - cx25840_write4(client, DIF_BPF_COEFF67, 0x002f0061); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff7bff79); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x011e007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe08ffe8); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f9ff28); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17026a); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0479fb70); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbad0713); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x032ff672); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xff100b83); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff38b); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x063c0c04); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf5baf5f5); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0dcc06ae); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xefcdfda8); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 13700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd0012); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0004ffc8); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00100078); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffacff3e); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e200f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe39ff35); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f10017); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd30156); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0521fc7f); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa9c0638); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x0499f6ee); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfd7a0b7c); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f325); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x04f40cb3); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf69af537); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0d5a073f); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xefecfd72); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 13800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0001fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa000e); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0011ffcb); - cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0007f); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffe7ff19); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x008f014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe94fe93); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b00105); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3002f); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0585fdb7); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9c10525); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x05def7a8); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfbf20b3c); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7f2e9); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x03a00d48); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf787f484); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0cdf07cd); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf00dfd3c); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 13900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80008); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001bffd7); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffd10076); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0026ff0e); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x002c0184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff0ffe10); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x023b01e0); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17ff06); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x05a2ff09); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf92703e4); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x06f4f89b); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa820ac5); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251f2d9); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x02430dc3); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf881f3dc); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0c5c0859); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf031fd06); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 14000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80001); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0021ffe8); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffba005d); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0060ff1f); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffc40198); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xffa0fdb5); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x019a029a); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fdea); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x05750067); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8d4027f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x07d4f9c0); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf9320a1a); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2f2f3); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x00df0e22); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf986f341); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0bd108e2); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf058fcd1); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 14100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffa); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0021fffd); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffac0038); - cx25840_write4(client, DIF_BPF_COEFF89, 0x008eff4a); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff630184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x003afd8b); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x00da0326); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fced); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x050101c0); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8cb0103); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x0876fb10); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf80a093e); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543f338); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xff7a0e66); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfa94f2b2); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0b3f0967); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf081fc9b); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 14200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbfff3); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001d0013); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffaa000b); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00aaff89); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff13014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x00cefd95); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x000a037b); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fc1d); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x044c0305); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf90cff7e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08d5fc81); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7100834); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x069ff3a7); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfe160e8d); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfbaaf231); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0aa509e9); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0adfc65); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 14300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0xffffffef); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00140025); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ffdd); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00b2ffd6); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedb00f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0150fdd3); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xff380391); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb85); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x035e0426); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf994fdfe); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08eefe0b); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6490702); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1f43e); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfcb60e97); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfcc6f1be); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0a040a67); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0dbfc30); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 14400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0002ffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00070033); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ffb4); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00a40027); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec3007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01b4fe3f); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe760369); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb2e); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x02450518); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa5ffc90); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08c1ffa1); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5bc05ae); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902f4fc); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfb600e85); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfde7f15a); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x095d0ae2); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf10cfbfb); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 14500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0005ffef); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfffa0038); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff95); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00820074); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecc0000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f0fed0); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdd20304); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfb1d); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x010e05ce); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb64fb41); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x084e013b); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf569043e); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a00f5dd); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfa150e55); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xff0bf104); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x08b00b59); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf13ffbc6); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 14600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fff4); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffed0035); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ff83); - cx25840_write4(client, DIF_BPF_COEFF89, 0x005000b4); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef6ff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01ffff7a); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd580269); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fb53); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xffca0640); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc99fa1e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x079a02cb); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55502ba); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad5f6e0); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf8d90e0a); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0031f0bd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x07fd0bcb); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf174fb91); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 14700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0009fffb); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe4002a); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ff82); - cx25840_write4(client, DIF_BPF_COEFF89, 0x001400e0); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff3cff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e10030); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd1201a4); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fbcd); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe88066a); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfdf1f92f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x06aa0449); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf57e0128); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7ef801); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf7b00da2); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0156f086); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x07450c39); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1acfb5c); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 14800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00080002); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffdf0019); - cx25840_write4(client, DIF_BPF_COEFF67, 0x003fff92); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffd600f1); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff96feb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x019700e1); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd0500c2); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0fc84); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd590649); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xff5df87f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x058505aa); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5e4ff91); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf9f93c); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf69d0d20); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0279f05e); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x06880ca3); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1e6fb28); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 14900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00060009); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffdf0004); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0051ffb0); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff9d00e8); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfffcfe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01280180); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd32ffd2); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413fd6e); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc4d05df); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x00d1f812); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x043506e4); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf685fdfb); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c43fa8d); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf5a10c83); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0399f046); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x05c70d08); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf222faf3); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 15000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0003000f); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe5ffef); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0057ffd9); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff7000c4); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0062fe68); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x009e01ff); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd95fee6); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0435fe7d); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb710530); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x023cf7ee); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x02c307ef); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf75efc70); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5cfbef); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf4c10bce); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x04b3f03f); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x05030d69); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf261fabf); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 15100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0012); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffefffdc); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00510006); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff540089); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00befe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x00060253); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe27fe0d); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413ffa2); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfad10446); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0390f812); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x013b08c3); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf868faf6); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c43fd5f); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3fd0b02); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x05c7f046); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x043b0dc4); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2a1fa8b); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 15200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0001fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc0012); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfffbffce); - cx25840_write4(client, DIF_BPF_COEFF67, 0x003f0033); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff4e003f); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0106feb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff6e0276); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfeddfd56); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b000cc); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa740329); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x04bff87f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xffaa095d); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf99ef995); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf9fed8); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3590a1f); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x06d2f05e); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x03700e1b); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2e4fa58); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 15300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9000f); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0009ffc8); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00250059); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff5effee); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0132ff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfee30265); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xffaafccf); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x031101eb); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa6001e8); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x05bdf92f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe1b09b6); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfafaf852); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0055); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2d50929); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x07d3f086); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x02a30e6c); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf329fa24); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 15400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80009); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0015ffca); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00050074); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff81ff9f); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x013dff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe710221); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x007cfc80); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x024102ed); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa940090); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0680fa1e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc9b09cd); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfc73f736); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad501d0); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2740820); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x08c9f0bd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x01d40eb9); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf371f9f1); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 15500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80002); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001effd5); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5007f); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffb4ff5b); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x01280000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2401b0); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0146fc70); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d03c6); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb10ff32); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0701fb41); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb3709a1); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe00f644); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000345); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2350708); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x09b2f104); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x01050eff); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf3baf9be); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 15600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffb); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0022ffe6); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9007a); - cx25840_write4(client, DIF_BPF_COEFF89, 0xfff0ff29); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f2007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01011b); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x01f6fc9e); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440467); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbccfdde); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0738fc90); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9f70934); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xff99f582); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x090204b0); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21a05e1); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0a8df15a); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x00340f41); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf405f98b); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 15700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcfff4); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0020fffa); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffb40064); - cx25840_write4(client, DIF_BPF_COEFF89, 0x002fff11); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00a400f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0d006e); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0281fd09); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3604c9); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcbffca2); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0726fdfe); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8e80888); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0134f4f3); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1060c); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf22304af); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b59f1be); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xff640f7d); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf452f959); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 15800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0000fff0); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001a0010); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffaa0041); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0067ff13); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0043014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe46ffb9); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02dbfda8); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3504e5); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfddcfb8d); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c9ff7e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf81107a2); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c9f49a); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0753); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2500373); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c14f231); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe930fb3); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4a1f927); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 15900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0003ffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0x000f0023); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffac0016); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0093ff31); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffdc0184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea6ff09); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fdfe70); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd5104ba); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xff15faac); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x06270103); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7780688); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x044df479); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430883); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a00231); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cbef2b2); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc40fe3); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4f2f8f5); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 16000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0006ffef); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00020031); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffe8); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00adff66); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff790198); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff26fe6e); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02e5ff55); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99044a); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x005bfa09); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0545027f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7230541); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b8f490); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20997); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf31300eb); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d55f341); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6100e); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf544f8c3); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - } + coeffs = ifhz_coeffs[(ifHz - 3000000) / 100000]; + cx25840_write4(client, DIF_BPF_COEFF01, coeffs[0]); + cx25840_write4(client, DIF_BPF_COEFF23, coeffs[1]); + cx25840_write4(client, DIF_BPF_COEFF45, coeffs[2]); + cx25840_write4(client, DIF_BPF_COEFF67, coeffs[3]); + cx25840_write4(client, DIF_BPF_COEFF89, coeffs[4]); + cx25840_write4(client, DIF_BPF_COEFF1011, coeffs[5]); + cx25840_write4(client, DIF_BPF_COEFF1213, coeffs[6]); + cx25840_write4(client, DIF_BPF_COEFF1415, coeffs[7]); + cx25840_write4(client, DIF_BPF_COEFF1617, coeffs[8]); + cx25840_write4(client, DIF_BPF_COEFF1819, coeffs[9]); + cx25840_write4(client, DIF_BPF_COEFF2021, coeffs[10]); + cx25840_write4(client, DIF_BPF_COEFF2223, coeffs[11]); + cx25840_write4(client, DIF_BPF_COEFF2425, coeffs[12]); + cx25840_write4(client, DIF_BPF_COEFF2627, coeffs[13]); + cx25840_write4(client, DIF_BPF_COEFF2829, coeffs[14]); + cx25840_write4(client, DIF_BPF_COEFF3031, coeffs[15]); + cx25840_write4(client, DIF_BPF_COEFF3233, coeffs[16]); + cx25840_write4(client, DIF_BPF_COEFF3435, coeffs[17]); + cx25840_write4(client, DIF_BPF_COEFF36, coeffs[18]); } static void cx23888_std_setup(struct i2c_client *client) -- GitLab From d27bb0246e5356dbef4d923e72c680bf893885a8 Mon Sep 17 00:00:00 2001 From: Li Zetao Date: Thu, 10 Aug 2023 19:52:20 +0800 Subject: [PATCH 0304/1451] media: nxp: Use devm_kmemdup to replace devm_kmalloc + memcpy Use the helper function devm_kmemdup() rather than duplicating its implementation, which helps to enhance code readability. Signed-off-by: Li Zetao Signed-off-by: Hans Verkuil --- drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c index 81be744e9f1b5..f73facb97dc50 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c @@ -406,12 +406,10 @@ static int mxc_isi_clk_get(struct mxc_isi_dev *isi) * sizeof(*isi->clks); int ret; - isi->clks = devm_kmalloc(isi->dev, size, GFP_KERNEL); + isi->clks = devm_kmemdup(isi->dev, isi->pdata->clks, size, GFP_KERNEL); if (!isi->clks) return -ENOMEM; - memcpy(isi->clks, isi->pdata->clks, size); - ret = devm_clk_bulk_get(isi->dev, isi->pdata->num_clks, isi->clks); if (ret < 0) { -- GitLab From 29d3e0b8bdb5dae76e529c70c06a2132d9c39f86 Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Fri, 11 Aug 2023 10:49:45 +0800 Subject: [PATCH 0305/1451] media: staging: media: sunxi: cedrus: Remove redundant of_match_ptr() The driver depends on CONFIG_OF, it is not necessary to use of_match_ptr() here. Signed-off-by: Ruan Jinjie Acked-by: Jernej Skrabec Acked-by: Paul Kocialkowski Signed-off-by: Hans Verkuil --- drivers/staging/media/sunxi/cedrus/cedrus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 8e248d4a0aecf..f52df68360452 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -708,7 +708,7 @@ static struct platform_driver cedrus_driver = { .remove_new = cedrus_remove, .driver = { .name = CEDRUS_NAME, - .of_match_table = of_match_ptr(cedrus_dt_match), + .of_match_table = cedrus_dt_match, .pm = &cedrus_dev_pm_ops, }, }; -- GitLab From 99e6eaab4c8440eaa6badb83e8e18923c2580c07 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 15 Aug 2023 08:07:37 +0200 Subject: [PATCH 0306/1451] media: dt-bindings: samsung,exynos4212-fimc-is: replace duplicate pmu node with phandle The FIMC IS camera must access the PMU (Power Management Unit) IO memory to control camera power. This was achieved by duplicating the PMU node as its child like: soc@0 { system-controller@10020000 { ... }; // Real PMU camera@11800000 { fimc-is@12000000 { // FIMC IS camera node pmu@10020000 { reg = <0x10020000 0x3000>; // Fake PMU node }; }; }; }; This is not a correct representation of the hardware. Mapping the PMU (Power Management Unit) IO memory should be via syscon-like phandle (samsung,pmu-syscon, already used for other drivers), not by duplicating "pmu" Devicetree node inside the FIMC IS. Reviewed-by: Rob Herring Signed-off-by: Krzysztof Kozlowski Signed-off-by: Hans Verkuil --- .../media/samsung,exynos4212-fimc-is.yaml | 15 ++++++++++----- .../devicetree/bindings/media/samsung,fimc.yaml | 5 +---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/media/samsung,exynos4212-fimc-is.yaml b/Documentation/devicetree/bindings/media/samsung,exynos4212-fimc-is.yaml index 3691cd4962b26..3a5ff3f470603 100644 --- a/Documentation/devicetree/bindings/media/samsung,exynos4212-fimc-is.yaml +++ b/Documentation/devicetree/bindings/media/samsung,exynos4212-fimc-is.yaml @@ -75,13 +75,20 @@ properties: power-domains: maxItems: 1 + samsung,pmu-syscon: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Power Management Unit (PMU) system controller interface, used to + power/start the ISP. + patternProperties: "^pmu@[0-9a-f]+$": type: object additionalProperties: false + deprecated: true description: Node representing the SoC's Power Management Unit (duplicated with the - correct PMU node in the SoC). + correct PMU node in the SoC). Deprecated, use samsung,pmu-syscon. properties: reg: @@ -131,6 +138,7 @@ required: - clock-names - interrupts - ranges + - samsung,pmu-syscon - '#size-cells' additionalProperties: false @@ -179,15 +187,12 @@ examples: <&sysmmu_fimc_fd>, <&sysmmu_fimc_mcuctl>; iommu-names = "isp", "drc", "fd", "mcuctl"; power-domains = <&pd_isp>; + samsung,pmu-syscon = <&pmu_system_controller>; #address-cells = <1>; #size-cells = <1>; ranges; - pmu@10020000 { - reg = <0x10020000 0x3000>; - }; - i2c-isp@12140000 { compatible = "samsung,exynos4212-i2c-isp"; reg = <0x12140000 0x100>; diff --git a/Documentation/devicetree/bindings/media/samsung,fimc.yaml b/Documentation/devicetree/bindings/media/samsung,fimc.yaml index 79ff6d83a9fd6..530a08f5d3fe5 100644 --- a/Documentation/devicetree/bindings/media/samsung,fimc.yaml +++ b/Documentation/devicetree/bindings/media/samsung,fimc.yaml @@ -236,15 +236,12 @@ examples: <&sysmmu_fimc_fd>, <&sysmmu_fimc_mcuctl>; iommu-names = "isp", "drc", "fd", "mcuctl"; power-domains = <&pd_isp>; + samsung,pmu-syscon = <&pmu_system_controller>; #address-cells = <1>; #size-cells = <1>; ranges; - pmu@10020000 { - reg = <0x10020000 0x3000>; - }; - i2c-isp@12140000 { compatible = "samsung,exynos4212-i2c-isp"; reg = <0x12140000 0x100>; -- GitLab From 6c378c24921e659203d8d4c7ca5c495458c92dfb Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 15 Aug 2023 08:07:38 +0200 Subject: [PATCH 0307/1451] media: dt-bindings: samsung,fimc: correct unit addresses in DTS example The camera node's ranges property and unit addresses of its children were not correct. If camera is @11800000, then its fimc child is @0. Acked-by: Conor Dooley Signed-off-by: Krzysztof Kozlowski Signed-off-by: Hans Verkuil --- .../bindings/media/samsung,fimc.yaml | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/media/samsung,fimc.yaml b/Documentation/devicetree/bindings/media/samsung,fimc.yaml index 530a08f5d3fe5..88b176d594e2c 100644 --- a/Documentation/devicetree/bindings/media/samsung,fimc.yaml +++ b/Documentation/devicetree/bindings/media/samsung,fimc.yaml @@ -117,7 +117,7 @@ examples: #clock-cells = <1>; #address-cells = <1>; #size-cells = <1>; - ranges = <0x0 0x0 0x18000000>; + ranges = <0x0 0x0 0xba1000>; clocks = <&clock CLK_SCLK_CAM0>, <&clock CLK_SCLK_CAM1>, <&clock CLK_PIXELASYNCM0>, <&clock CLK_PIXELASYNCM1>; @@ -132,9 +132,9 @@ examples: pinctrl-0 = <&cam_port_a_clk_active &cam_port_b_clk_active>; pinctrl-names = "default"; - fimc@11800000 { + fimc@0 { compatible = "samsung,exynos4212-fimc"; - reg = <0x11800000 0x1000>; + reg = <0x00000000 0x1000>; interrupts = ; clocks = <&clock CLK_FIMC0>, <&clock CLK_SCLK_FIMC0>; @@ -151,9 +151,9 @@ examples: /* ... FIMC 1-3 */ - csis@11880000 { + csis@80000 { compatible = "samsung,exynos4210-csis"; - reg = <0x11880000 0x4000>; + reg = <0x00080000 0x4000>; interrupts = ; clocks = <&clock CLK_CSIS0>, <&clock CLK_SCLK_CSIS0>; @@ -186,9 +186,9 @@ examples: /* ... CSIS 1 */ - fimc-lite@12390000 { + fimc-lite@b90000 { compatible = "samsung,exynos4212-fimc-lite"; - reg = <0x12390000 0x1000>; + reg = <0xb90000 0x1000>; interrupts = ; power-domains = <&pd_isp>; clocks = <&isp_clock CLK_ISP_FIMC_LITE0>; @@ -198,9 +198,9 @@ examples: /* ... FIMC-LITE 1 */ - fimc-is@12000000 { + fimc-is@800000 { compatible = "samsung,exynos4212-fimc-is"; - reg = <0x12000000 0x260000>; + reg = <0x00800000 0x260000>; interrupts = , ; clocks = <&isp_clock CLK_ISP_FIMC_LITE0>, @@ -242,9 +242,9 @@ examples: #size-cells = <1>; ranges; - i2c-isp@12140000 { + i2c-isp@940000 { compatible = "samsung,exynos4212-i2c-isp"; - reg = <0x12140000 0x100>; + reg = <0x00940000 0x100>; clocks = <&isp_clock CLK_ISP_I2C1_ISP>; clock-names = "i2c_isp"; pinctrl-0 = <&fimc_is_i2c1>; -- GitLab From 292f83dc68442c8a33cdc6358795786234bf2f50 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 15 Aug 2023 08:07:39 +0200 Subject: [PATCH 0308/1451] media: exynos4-is: fimc-is: replace duplicate pmu node with phandle Devicetree for the FIMC IS camera included duplicated PMU node as its child like: soc@0 { system-controller@10020000 { ... }; // Real PMU camera@11800000 { fimc-is@12000000 { // FIMC IS camera node pmu@10020000 { reg = <0x10020000 0x3000>; // Fake PMU node }; }; }; }; This is not a correct representation of the hardware. Mapping the PMU (Power Management Unit) IO memory should be via syscon-like phandle (samsung,pmu-syscon, already used for other drivers), not by duplicating "pmu" Devicetree node inside the FIMC IS. Backward compatibility is preserved. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Hans Verkuil --- .../platform/samsung/exynos4-is/fimc-is.c | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is.c b/drivers/media/platform/samsung/exynos4-is/fimc-is.c index 530a148fe4d38..a08c87ef6e2d8 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-is.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-is.c @@ -767,12 +767,32 @@ static void fimc_is_debugfs_create(struct fimc_is *is) static int fimc_is_runtime_resume(struct device *dev); static int fimc_is_runtime_suspend(struct device *dev); +static void __iomem *fimc_is_get_pmu_regs(struct device *dev) +{ + struct device_node *node; + void __iomem *regs; + + node = of_parse_phandle(dev->of_node, "samsung,pmu-syscon", 0); + if (!node) { + node = of_get_child_by_name(dev->of_node, "pmu"); + if (!node) + return IOMEM_ERR_PTR(-ENODEV); + dev_warn(dev, "Found PMU node via deprecated method, update your DTB\n"); + } + + regs = of_iomap(node, 0); + of_node_put(node); + if (!regs) + return IOMEM_ERR_PTR(-ENOMEM); + + return regs; +} + static int fimc_is_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct fimc_is *is; struct resource res; - struct device_node *node; int ret; is = devm_kzalloc(&pdev->dev, sizeof(*is), GFP_KERNEL); @@ -794,14 +814,9 @@ static int fimc_is_probe(struct platform_device *pdev) if (IS_ERR(is->regs)) return PTR_ERR(is->regs); - node = of_get_child_by_name(dev->of_node, "pmu"); - if (!node) - return -ENODEV; - - is->pmu_regs = of_iomap(node, 0); - of_node_put(node); - if (!is->pmu_regs) - return -ENOMEM; + is->pmu_regs = fimc_is_get_pmu_regs(dev); + if (IS_ERR(is->pmu_regs)) + return PTR_ERR(is->pmu_regs); is->irq = irq_of_parse_and_map(dev->of_node, 0); if (!is->irq) { -- GitLab From 6c4ef82846066bf70a07026fe56e9f209a9a5953 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 15 Aug 2023 13:14:46 +0100 Subject: [PATCH 0309/1451] media: mediatek: vcodec: fix spelling mistake "resonable" -> "reasonable" There are a couple of spelling mistakes in pr_err error messages. Fix them. Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil --- .../media/platform/mediatek/vcodec/common/mtk_vcodec_fw_scp.c | 2 +- .../media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_scp.c b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_scp.c index 9e744d07a1e8e..6bbe55de6ce9a 100644 --- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_scp.c +++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_scp.c @@ -68,7 +68,7 @@ struct mtk_vcodec_fw *mtk_vcodec_fw_scp_init(void *priv, enum mtk_vcodec_fw_use plat_dev = dec_dev->plat_dev; } else { - pr_err("Invalid fw_use %d (use a resonable fw id here)\n", fw_use); + pr_err("Invalid fw_use %d (use a reasonable fw id here)\n", fw_use); return ERR_PTR(-EINVAL); } diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c index 5e03b08865599..9f6e4b59455da 100644 --- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c +++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c @@ -109,7 +109,7 @@ struct mtk_vcodec_fw *mtk_vcodec_fw_vpu_init(void *priv, enum mtk_vcodec_fw_use plat_dev = dec_dev->plat_dev; rst_id = VPU_RST_DEC; } else { - pr_err("Invalid fw_use %d (use a resonable fw id here)\n", fw_use); + pr_err("Invalid fw_use %d (use a reasonable fw id here)\n", fw_use); return ERR_PTR(-EINVAL); } -- GitLab From ba85aea885a195b1b6c802a4ff8edf4e014e54b5 Mon Sep 17 00:00:00 2001 From: Yu Liao Date: Wed, 16 Aug 2023 14:31:43 +0800 Subject: [PATCH 0310/1451] media: use struct_size() helper Prefer struct_size() over open-coded versions of idiom: sizeof(struct-with-flex-array) + sizeof(typeof-flex-array-elements) * count where count is the max number of items the flexible array is supposed to contain. Signed-off-by: Yu Liao Reviewed-by: Tomasz Figa Signed-off-by: Hans Verkuil --- drivers/media/common/videobuf2/frame_vector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/common/videobuf2/frame_vector.c b/drivers/media/common/videobuf2/frame_vector.c index fd87747be9b17..41f289c75cbb6 100644 --- a/drivers/media/common/videobuf2/frame_vector.c +++ b/drivers/media/common/videobuf2/frame_vector.c @@ -159,7 +159,7 @@ EXPORT_SYMBOL(frame_vector_to_pfns); struct frame_vector *frame_vector_create(unsigned int nr_frames) { struct frame_vector *vec; - int size = sizeof(struct frame_vector) + sizeof(void *) * nr_frames; + int size = struct_size(vec, ptrs, nr_frames); if (WARN_ON_ONCE(nr_frames == 0)) return NULL; -- GitLab From 0c7b8c5c2aed26234b281e167f07ded444246116 Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Thu, 17 Aug 2023 21:43:54 +0800 Subject: [PATCH 0311/1451] media: imx-jpeg: Remove unused declarations These are never implemented, remove them. Signed-off-by: Yue Haibing Signed-off-by: Hans Verkuil --- drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h index a2b4fb9e29e7d..d579c804b0479 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h @@ -115,28 +115,17 @@ void print_cast_status(struct device *dev, void __iomem *reg, void print_wrapper_info(struct device *dev, void __iomem *reg); void mxc_jpeg_sw_reset(void __iomem *reg); int mxc_jpeg_enable(void __iomem *reg); -void wait_frmdone(struct device *dev, void __iomem *reg); void mxc_jpeg_enc_mode_conf(struct device *dev, void __iomem *reg, u8 extseq); void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg, u8 extseq); void mxc_jpeg_enc_set_quality(struct device *dev, void __iomem *reg, u8 quality); void mxc_jpeg_dec_mode_go(struct device *dev, void __iomem *reg); -int mxc_jpeg_get_slot(void __iomem *reg); -u32 mxc_jpeg_get_offset(void __iomem *reg, int slot); void mxc_jpeg_enable_slot(void __iomem *reg, int slot); void mxc_jpeg_set_l_endian(void __iomem *reg, int le); void mxc_jpeg_enable_irq(void __iomem *reg, int slot); void mxc_jpeg_disable_irq(void __iomem *reg, int slot); -int mxc_jpeg_set_input(void __iomem *reg, u32 in_buf, u32 bufsize); -int mxc_jpeg_set_output(void __iomem *reg, u16 out_pitch, u32 out_buf, - u16 w, u16 h); -void mxc_jpeg_set_config_mode(void __iomem *reg, int config_mode); -int mxc_jpeg_set_params(struct mxc_jpeg_desc *desc, u32 bufsize, u16 - out_pitch, u32 format); void mxc_jpeg_set_bufsize(struct mxc_jpeg_desc *desc, u32 bufsize); void mxc_jpeg_set_res(struct mxc_jpeg_desc *desc, u16 w, u16 h); void mxc_jpeg_set_line_pitch(struct mxc_jpeg_desc *desc, u32 line_pitch); void mxc_jpeg_set_desc(u32 desc, void __iomem *reg, int slot); void mxc_jpeg_clr_desc(void __iomem *reg, int slot); -void mxc_jpeg_set_regs_from_desc(struct mxc_jpeg_desc *desc, - void __iomem *reg); #endif -- GitLab From 785c4aa400cb81cb96793771bb629c6582c71f21 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 13 Aug 2023 10:20:49 +0200 Subject: [PATCH 0312/1451] media: atomisp: remove left-over videobuf include This source still included the media/videobuf-vmalloc.h header, even though it is no longer used. Since the old videobuf framework is about to be removed, delete this include first. Signed-off-by: Hans Verkuil Reviewed-by: Hans de Goede --- drivers/staging/media/atomisp/pci/atomisp_compat_css20.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c index b97ec85aa0bab..0c02f41e1a1f8 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c +++ b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c @@ -16,7 +16,6 @@ * */ -#include #include #include -- GitLab From 2a2fffb488a3c5ea9c06d0b572c90c4aa78709b6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 13 Aug 2023 10:22:54 +0200 Subject: [PATCH 0313/1451] media: remove the old videobuf framework The last driver that still used this old framework has been converted to the videobuf2 framework. So it is now time to delete the old videobuf code. Signed-off-by: Hans Verkuil Reviewed-by: Hans de Goede --- Documentation/driver-api/media/v4l2-core.rst | 1 - Documentation/driver-api/media/v4l2-dev.rst | 8 - .../driver-api/media/v4l2-videobuf.rst | 403 ------ .../zh_CN/video4linux/v4l2-framework.txt | 12 - drivers/media/v4l2-core/Kconfig | 16 - drivers/media/v4l2-core/Makefile | 5 - drivers/media/v4l2-core/videobuf-core.c | 1198 ----------------- drivers/media/v4l2-core/videobuf-dma-contig.c | 402 ------ drivers/media/v4l2-core/videobuf-dma-sg.c | 681 ---------- drivers/media/v4l2-core/videobuf-vmalloc.c | 326 ----- include/media/videobuf-core.h | 233 ---- include/media/videobuf-dma-contig.h | 30 - include/media/videobuf-dma-sg.h | 102 -- include/media/videobuf-vmalloc.h | 43 - 14 files changed, 3460 deletions(-) delete mode 100644 Documentation/driver-api/media/v4l2-videobuf.rst delete mode 100644 drivers/media/v4l2-core/videobuf-core.c delete mode 100644 drivers/media/v4l2-core/videobuf-dma-contig.c delete mode 100644 drivers/media/v4l2-core/videobuf-dma-sg.c delete mode 100644 drivers/media/v4l2-core/videobuf-vmalloc.c delete mode 100644 include/media/videobuf-core.h delete mode 100644 include/media/videobuf-dma-contig.h delete mode 100644 include/media/videobuf-dma-sg.h delete mode 100644 include/media/videobuf-vmalloc.h diff --git a/Documentation/driver-api/media/v4l2-core.rst b/Documentation/driver-api/media/v4l2-core.rst index 239045ecc8f42..58cba831ade5a 100644 --- a/Documentation/driver-api/media/v4l2-core.rst +++ b/Documentation/driver-api/media/v4l2-core.rst @@ -13,7 +13,6 @@ Video4Linux devices v4l2-subdev v4l2-event v4l2-controls - v4l2-videobuf v4l2-videobuf2 v4l2-dv-timings v4l2-flash-led-class diff --git a/Documentation/driver-api/media/v4l2-dev.rst b/Documentation/driver-api/media/v4l2-dev.rst index 99e3b5fa74447..d5cb19b21a9f7 100644 --- a/Documentation/driver-api/media/v4l2-dev.rst +++ b/Documentation/driver-api/media/v4l2-dev.rst @@ -157,14 +157,6 @@ changing the e.g. exposure of the webcam. Of course, you can always do all the locking yourself by leaving both lock pointers at ``NULL``. -If you use the old :ref:`videobuf framework ` then you must -pass the :c:type:`video_device`->lock to the videobuf queue initialize -function: if videobuf has to wait for a frame to arrive, then it will -temporarily unlock the lock and relock it afterwards. If your driver also -waits in the code, then you should do the same to allow other -processes to access the device node while the first process is waiting for -something. - In the case of :ref:`videobuf2 ` you will need to implement the ``wait_prepare()`` and ``wait_finish()`` callbacks to unlock/lock if applicable. If you use the ``queue->lock`` pointer, then you can use the helper functions diff --git a/Documentation/driver-api/media/v4l2-videobuf.rst b/Documentation/driver-api/media/v4l2-videobuf.rst deleted file mode 100644 index 4b1d84eefeb8b..0000000000000 --- a/Documentation/driver-api/media/v4l2-videobuf.rst +++ /dev/null @@ -1,403 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -.. _vb_framework: - -Videobuf Framework -================== - -Author: Jonathan Corbet - -Current as of 2.6.33 - -.. note:: - - The videobuf framework was deprecated in favor of videobuf2. Shouldn't - be used on new drivers. - -Introduction ------------- - -The videobuf layer functions as a sort of glue layer between a V4L2 driver -and user space. It handles the allocation and management of buffers for -the storage of video frames. There is a set of functions which can be used -to implement many of the standard POSIX I/O system calls, including read(), -poll(), and, happily, mmap(). Another set of functions can be used to -implement the bulk of the V4L2 ioctl() calls related to streaming I/O, -including buffer allocation, queueing and dequeueing, and streaming -control. Using videobuf imposes a few design decisions on the driver -author, but the payback comes in the form of reduced code in the driver and -a consistent implementation of the V4L2 user-space API. - -Buffer types ------------- - -Not all video devices use the same kind of buffers. In fact, there are (at -least) three common variations: - - - Buffers which are scattered in both the physical and (kernel) virtual - address spaces. (Almost) all user-space buffers are like this, but it - makes great sense to allocate kernel-space buffers this way as well when - it is possible. Unfortunately, it is not always possible; working with - this kind of buffer normally requires hardware which can do - scatter/gather DMA operations. - - - Buffers which are physically scattered, but which are virtually - contiguous; buffers allocated with vmalloc(), in other words. These - buffers are just as hard to use for DMA operations, but they can be - useful in situations where DMA is not available but virtually-contiguous - buffers are convenient. - - - Buffers which are physically contiguous. Allocation of this kind of - buffer can be unreliable on fragmented systems, but simpler DMA - controllers cannot deal with anything else. - -Videobuf can work with all three types of buffers, but the driver author -must pick one at the outset and design the driver around that decision. - -[It's worth noting that there's a fourth kind of buffer: "overlay" buffers -which are located within the system's video memory. The overlay -functionality is considered to be deprecated for most use, but it still -shows up occasionally in system-on-chip drivers where the performance -benefits merit the use of this technique. Overlay buffers can be handled -as a form of scattered buffer, but there are very few implementations in -the kernel and a description of this technique is currently beyond the -scope of this document.] - -Data structures, callbacks, and initialization ----------------------------------------------- - -Depending on which type of buffers are being used, the driver should -include one of the following files: - -.. code-block:: none - - /* Physically scattered */ - /* vmalloc() buffers */ - /* Physically contiguous */ - -The driver's data structure describing a V4L2 device should include a -struct videobuf_queue instance for the management of the buffer queue, -along with a list_head for the queue of available buffers. There will also -need to be an interrupt-safe spinlock which is used to protect (at least) -the queue. - -The next step is to write four simple callbacks to help videobuf deal with -the management of buffers: - -.. code-block:: none - - struct videobuf_queue_ops { - int (*buf_setup)(struct videobuf_queue *q, - unsigned int *count, unsigned int *size); - int (*buf_prepare)(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field); - void (*buf_queue)(struct videobuf_queue *q, - struct videobuf_buffer *vb); - void (*buf_release)(struct videobuf_queue *q, - struct videobuf_buffer *vb); - }; - -buf_setup() is called early in the I/O process, when streaming is being -initiated; its purpose is to tell videobuf about the I/O stream. The count -parameter will be a suggested number of buffers to use; the driver should -check it for rationality and adjust it if need be. As a practical rule, a -minimum of two buffers are needed for proper streaming, and there is -usually a maximum (which cannot exceed 32) which makes sense for each -device. The size parameter should be set to the expected (maximum) size -for each frame of data. - -Each buffer (in the form of a struct videobuf_buffer pointer) will be -passed to buf_prepare(), which should set the buffer's size, width, height, -and field fields properly. If the buffer's state field is -VIDEOBUF_NEEDS_INIT, the driver should pass it to: - -.. code-block:: none - - int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf); - -Among other things, this call will usually allocate memory for the buffer. -Finally, the buf_prepare() function should set the buffer's state to -VIDEOBUF_PREPARED. - -When a buffer is queued for I/O, it is passed to buf_queue(), which should -put it onto the driver's list of available buffers and set its state to -VIDEOBUF_QUEUED. Note that this function is called with the queue spinlock -held; if it tries to acquire it as well things will come to a screeching -halt. Yes, this is the voice of experience. Note also that videobuf may -wait on the first buffer in the queue; placing other buffers in front of it -could again gum up the works. So use list_add_tail() to enqueue buffers. - -Finally, buf_release() is called when a buffer is no longer intended to be -used. The driver should ensure that there is no I/O active on the buffer, -then pass it to the appropriate free routine(s): - -.. code-block:: none - - /* Scatter/gather drivers */ - int videobuf_dma_unmap(struct videobuf_queue *q, - struct videobuf_dmabuf *dma); - int videobuf_dma_free(struct videobuf_dmabuf *dma); - - /* vmalloc drivers */ - void videobuf_vmalloc_free (struct videobuf_buffer *buf); - - /* Contiguous drivers */ - void videobuf_dma_contig_free(struct videobuf_queue *q, - struct videobuf_buffer *buf); - -One way to ensure that a buffer is no longer under I/O is to pass it to: - -.. code-block:: none - - int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr); - -Here, vb is the buffer, non_blocking indicates whether non-blocking I/O -should be used (it should be zero in the buf_release() case), and intr -controls whether an interruptible wait is used. - -File operations ---------------- - -At this point, much of the work is done; much of the rest is slipping -videobuf calls into the implementation of the other driver callbacks. The -first step is in the open() function, which must initialize the -videobuf queue. The function to use depends on the type of buffer used: - -.. code-block:: none - - void videobuf_queue_sg_init(struct videobuf_queue *q, - struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv); - - void videobuf_queue_vmalloc_init(struct videobuf_queue *q, - struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv); - - void videobuf_queue_dma_contig_init(struct videobuf_queue *q, - struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv); - -In each case, the parameters are the same: q is the queue structure for the -device, ops is the set of callbacks as described above, dev is the device -structure for this video device, irqlock is an interrupt-safe spinlock to -protect access to the data structures, type is the buffer type used by the -device (cameras will use V4L2_BUF_TYPE_VIDEO_CAPTURE, for example), field -describes which field is being captured (often V4L2_FIELD_NONE for -progressive devices), msize is the size of any containing structure used -around struct videobuf_buffer, and priv is a private data pointer which -shows up in the priv_data field of struct videobuf_queue. Note that these -are void functions which, evidently, are immune to failure. - -V4L2 capture drivers can be written to support either of two APIs: the -read() system call and the rather more complicated streaming mechanism. As -a general rule, it is necessary to support both to ensure that all -applications have a chance of working with the device. Videobuf makes it -easy to do that with the same code. To implement read(), the driver need -only make a call to one of: - -.. code-block:: none - - ssize_t videobuf_read_one(struct videobuf_queue *q, - char __user *data, size_t count, - loff_t *ppos, int nonblocking); - - ssize_t videobuf_read_stream(struct videobuf_queue *q, - char __user *data, size_t count, - loff_t *ppos, int vbihack, int nonblocking); - -Either one of these functions will read frame data into data, returning the -amount actually read; the difference is that videobuf_read_one() will only -read a single frame, while videobuf_read_stream() will read multiple frames -if they are needed to satisfy the count requested by the application. A -typical driver read() implementation will start the capture engine, call -one of the above functions, then stop the engine before returning (though a -smarter implementation might leave the engine running for a little while in -anticipation of another read() call happening in the near future). - -The poll() function can usually be implemented with a direct call to: - -.. code-block:: none - - unsigned int videobuf_poll_stream(struct file *file, - struct videobuf_queue *q, - poll_table *wait); - -Note that the actual wait queue eventually used will be the one associated -with the first available buffer. - -When streaming I/O is done to kernel-space buffers, the driver must support -the mmap() system call to enable user space to access the data. In many -V4L2 drivers, the often-complex mmap() implementation simplifies to a -single call to: - -.. code-block:: none - - int videobuf_mmap_mapper(struct videobuf_queue *q, - struct vm_area_struct *vma); - -Everything else is handled by the videobuf code. - -The release() function requires two separate videobuf calls: - -.. code-block:: none - - void videobuf_stop(struct videobuf_queue *q); - int videobuf_mmap_free(struct videobuf_queue *q); - -The call to videobuf_stop() terminates any I/O in progress - though it is -still up to the driver to stop the capture engine. The call to -videobuf_mmap_free() will ensure that all buffers have been unmapped; if -so, they will all be passed to the buf_release() callback. If buffers -remain mapped, videobuf_mmap_free() returns an error code instead. The -purpose is clearly to cause the closing of the file descriptor to fail if -buffers are still mapped, but every driver in the 2.6.32 kernel cheerfully -ignores its return value. - -ioctl() operations ------------------- - -The V4L2 API includes a very long list of driver callbacks to respond to -the many ioctl() commands made available to user space. A number of these -- those associated with streaming I/O - turn almost directly into videobuf -calls. The relevant helper functions are: - -.. code-block:: none - - int videobuf_reqbufs(struct videobuf_queue *q, - struct v4l2_requestbuffers *req); - int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b); - int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b); - int videobuf_dqbuf(struct videobuf_queue *q, struct v4l2_buffer *b, - int nonblocking); - int videobuf_streamon(struct videobuf_queue *q); - int videobuf_streamoff(struct videobuf_queue *q); - -So, for example, a VIDIOC_REQBUFS call turns into a call to the driver's -vidioc_reqbufs() callback which, in turn, usually only needs to locate the -proper struct videobuf_queue pointer and pass it to videobuf_reqbufs(). -These support functions can replace a great deal of buffer management -boilerplate in a lot of V4L2 drivers. - -The vidioc_streamon() and vidioc_streamoff() functions will be a bit more -complex, of course, since they will also need to deal with starting and -stopping the capture engine. - -Buffer allocation ------------------ - -Thus far, we have talked about buffers, but have not looked at how they are -allocated. The scatter/gather case is the most complex on this front. For -allocation, the driver can leave buffer allocation entirely up to the -videobuf layer; in this case, buffers will be allocated as anonymous -user-space pages and will be very scattered indeed. If the application is -using user-space buffers, no allocation is needed; the videobuf layer will -take care of calling get_user_pages() and filling in the scatterlist array. - -If the driver needs to do its own memory allocation, it should be done in -the vidioc_reqbufs() function, *after* calling videobuf_reqbufs(). The -first step is a call to: - -.. code-block:: none - - struct videobuf_dmabuf *videobuf_to_dma(struct videobuf_buffer *buf); - -The returned videobuf_dmabuf structure (defined in -) includes a couple of relevant fields: - -.. code-block:: none - - struct scatterlist *sglist; - int sglen; - -The driver must allocate an appropriately-sized scatterlist array and -populate it with pointers to the pieces of the allocated buffer; sglen -should be set to the length of the array. - -Drivers using the vmalloc() method need not (and cannot) concern themselves -with buffer allocation at all; videobuf will handle those details. The -same is normally true of contiguous-DMA drivers as well; videobuf will -allocate the buffers (with dma_alloc_coherent()) when it sees fit. That -means that these drivers may be trying to do high-order allocations at any -time, an operation which is not always guaranteed to work. Some drivers -play tricks by allocating DMA space at system boot time; videobuf does not -currently play well with those drivers. - -As of 2.6.31, contiguous-DMA drivers can work with a user-supplied buffer, -as long as that buffer is physically contiguous. Normal user-space -allocations will not meet that criterion, but buffers obtained from other -kernel drivers, or those contained within huge pages, will work with these -drivers. - -Filling the buffers -------------------- - -The final part of a videobuf implementation has no direct callback - it's -the portion of the code which actually puts frame data into the buffers, -usually in response to interrupts from the device. For all types of -drivers, this process works approximately as follows: - - - Obtain the next available buffer and make sure that somebody is actually - waiting for it. - - - Get a pointer to the memory and put video data there. - - - Mark the buffer as done and wake up the process waiting for it. - -Step (1) above is done by looking at the driver-managed list_head structure -- the one which is filled in the buf_queue() callback. Because starting -the engine and enqueueing buffers are done in separate steps, it's possible -for the engine to be running without any buffers available - in the -vmalloc() case especially. So the driver should be prepared for the list -to be empty. It is equally possible that nobody is yet interested in the -buffer; the driver should not remove it from the list or fill it until a -process is waiting on it. That test can be done by examining the buffer's -done field (a wait_queue_head_t structure) with waitqueue_active(). - -A buffer's state should be set to VIDEOBUF_ACTIVE before being mapped for -DMA; that ensures that the videobuf layer will not try to do anything with -it while the device is transferring data. - -For scatter/gather drivers, the needed memory pointers will be found in the -scatterlist structure described above. Drivers using the vmalloc() method -can get a memory pointer with: - -.. code-block:: none - - void *videobuf_to_vmalloc(struct videobuf_buffer *buf); - -For contiguous DMA drivers, the function to use is: - -.. code-block:: none - - dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf); - -The contiguous DMA API goes out of its way to hide the kernel-space address -of the DMA buffer from drivers. - -The final step is to set the size field of the relevant videobuf_buffer -structure to the actual size of the captured image, set state to -VIDEOBUF_DONE, then call wake_up() on the done queue. At this point, the -buffer is owned by the videobuf layer and the driver should not touch it -again. - -Developers who are interested in more information can go into the relevant -header files; there are a few low-level functions declared there which have -not been talked about here. Note also that all of these calls are exported -GPL-only, so they will not be available to non-GPL kernel modules. diff --git a/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt b/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt index a88fcbc11eca6..9cc97ec75d7a4 100644 --- a/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt +++ b/Documentation/translations/zh_CN/video4linux/v4l2-framework.txt @@ -768,18 +768,6 @@ const char *video_device_node_name(struct video_device *vdev); 此功能,而非访问 video_device::num 和 video_device::minor 域。 -视频缓冲辅助函数 ---------------- - -v4l2 核心 API 提供了一个处理视频缓冲的标准方法(称为“videobuf”)。 -这些方法使驱动可以通过统一的方式实现 read()、mmap() 和 overlay()。 -目前在设备上支持视频缓冲的方法有分散/聚集 DMA(videobuf-dma-sg)、 -线性 DMA(videobuf-dma-contig)以及大多用于 USB 设备的用 vmalloc -分配的缓冲(videobuf-vmalloc)。 - -请参阅 Documentation/driver-api/media/v4l2-videobuf.rst,以获得更多关于 videobuf -层的使用信息。 - v4l2_fh 结构体 ------------- diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index f77ebd688cde7..331b8e535e5bb 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -82,19 +82,3 @@ config V4L2_CCI_I2C depends on I2C select REGMAP_I2C select V4L2_CCI - -# Used by drivers that need Videobuf modules -config VIDEOBUF_GEN - tristate - -config VIDEOBUF_DMA_SG - tristate - select VIDEOBUF_GEN - -config VIDEOBUF_VMALLOC - tristate - select VIDEOBUF_GEN - -config VIDEOBUF_DMA_CONTIG - tristate - select VIDEOBUF_GEN diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile index be2551705755e..2177b9d63a8ff 100644 --- a/drivers/media/v4l2-core/Makefile +++ b/drivers/media/v4l2-core/Makefile @@ -33,10 +33,5 @@ obj-$(CONFIG_V4L2_JPEG_HELPER) += v4l2-jpeg.o obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o obj-$(CONFIG_V4L2_VP9) += v4l2-vp9.o -obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o -obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o -obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o -obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o - obj-$(CONFIG_VIDEO_TUNER) += tuner.o obj-$(CONFIG_VIDEO_DEV) += v4l2-dv-timings.o videodev.o diff --git a/drivers/media/v4l2-core/videobuf-core.c b/drivers/media/v4l2-core/videobuf-core.c deleted file mode 100644 index 606a271bdd2dd..0000000000000 --- a/drivers/media/v4l2-core/videobuf-core.c +++ /dev/null @@ -1,1198 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * generic helper functions for handling video4linux capture buffers - * - * (c) 2007 Mauro Carvalho Chehab, - * - * Highly based on video-buf written originally by: - * (c) 2001,02 Gerd Knorr - * (c) 2006 Mauro Carvalho Chehab, - * (c) 2006 Ted Walther and John Sokol - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define MAGIC_BUFFER 0x20070728 -#define MAGIC_CHECK(is, should) \ - do { \ - if (unlikely((is) != (should))) { \ - printk(KERN_ERR \ - "magic mismatch: %x (expected %x)\n", \ - is, should); \ - BUG(); \ - } \ - } while (0) - -static int debug; -module_param(debug, int, 0644); - -MODULE_DESCRIPTION("helper module to manage video4linux buffers"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); - -#define dprintk(level, fmt, arg...) \ - do { \ - if (debug >= level) \ - printk(KERN_DEBUG "vbuf: " fmt, ## arg); \ - } while (0) - -/* --------------------------------------------------------------------- */ - -#define CALL(q, f, arg...) \ - ((q->int_ops->f) ? q->int_ops->f(arg) : 0) -#define CALLPTR(q, f, arg...) \ - ((q->int_ops->f) ? q->int_ops->f(arg) : NULL) - -struct videobuf_buffer *videobuf_alloc_vb(struct videobuf_queue *q) -{ - struct videobuf_buffer *vb; - - BUG_ON(q->msize < sizeof(*vb)); - - if (!q->int_ops || !q->int_ops->alloc_vb) { - printk(KERN_ERR "No specific ops defined!\n"); - BUG(); - } - - vb = q->int_ops->alloc_vb(q->msize); - if (NULL != vb) { - init_waitqueue_head(&vb->done); - vb->magic = MAGIC_BUFFER; - } - - return vb; -} -EXPORT_SYMBOL_GPL(videobuf_alloc_vb); - -static int state_neither_active_nor_queued(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - unsigned long flags; - bool rc; - - spin_lock_irqsave(q->irqlock, flags); - rc = vb->state != VIDEOBUF_ACTIVE && vb->state != VIDEOBUF_QUEUED; - spin_unlock_irqrestore(q->irqlock, flags); - return rc; -}; - -int videobuf_waiton(struct videobuf_queue *q, struct videobuf_buffer *vb, - int non_blocking, int intr) -{ - bool is_ext_locked; - int ret = 0; - - MAGIC_CHECK(vb->magic, MAGIC_BUFFER); - - if (non_blocking) { - if (state_neither_active_nor_queued(q, vb)) - return 0; - return -EAGAIN; - } - - is_ext_locked = q->ext_lock && mutex_is_locked(q->ext_lock); - - /* Release vdev lock to prevent this wait from blocking outside access to - the device. */ - if (is_ext_locked) - mutex_unlock(q->ext_lock); - if (intr) - ret = wait_event_interruptible(vb->done, - state_neither_active_nor_queued(q, vb)); - else - wait_event(vb->done, state_neither_active_nor_queued(q, vb)); - /* Relock */ - if (is_ext_locked) - mutex_lock(q->ext_lock); - - return ret; -} -EXPORT_SYMBOL_GPL(videobuf_waiton); - -int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf) -{ - MAGIC_CHECK(vb->magic, MAGIC_BUFFER); - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - return CALL(q, iolock, q, vb, fbuf); -} -EXPORT_SYMBOL_GPL(videobuf_iolock); - -void *videobuf_queue_to_vaddr(struct videobuf_queue *q, - struct videobuf_buffer *buf) -{ - if (q->int_ops->vaddr) - return q->int_ops->vaddr(buf); - return NULL; -} -EXPORT_SYMBOL_GPL(videobuf_queue_to_vaddr); - -/* --------------------------------------------------------------------- */ - - -void videobuf_queue_core_init(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct videobuf_qtype_ops *int_ops, - struct mutex *ext_lock) -{ - BUG_ON(!q); - memset(q, 0, sizeof(*q)); - q->irqlock = irqlock; - q->ext_lock = ext_lock; - q->dev = dev; - q->type = type; - q->field = field; - q->msize = msize; - q->ops = ops; - q->priv_data = priv; - q->int_ops = int_ops; - - /* All buffer operations are mandatory */ - BUG_ON(!q->ops->buf_setup); - BUG_ON(!q->ops->buf_prepare); - BUG_ON(!q->ops->buf_queue); - BUG_ON(!q->ops->buf_release); - - /* Lock is mandatory for queue_cancel to work */ - BUG_ON(!irqlock); - - /* Having implementations for abstract methods are mandatory */ - BUG_ON(!q->int_ops); - - mutex_init(&q->vb_lock); - init_waitqueue_head(&q->wait); - INIT_LIST_HEAD(&q->stream); -} -EXPORT_SYMBOL_GPL(videobuf_queue_core_init); - -/* Locking: Only usage in bttv unsafe find way to remove */ -int videobuf_queue_is_busy(struct videobuf_queue *q) -{ - int i; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - if (q->streaming) { - dprintk(1, "busy: streaming active\n"); - return 1; - } - if (q->reading) { - dprintk(1, "busy: pending read #1\n"); - return 1; - } - if (q->read_buf) { - dprintk(1, "busy: pending read #2\n"); - return 1; - } - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (q->bufs[i]->map) { - dprintk(1, "busy: buffer #%d mapped\n", i); - return 1; - } - if (q->bufs[i]->state == VIDEOBUF_QUEUED) { - dprintk(1, "busy: buffer #%d queued\n", i); - return 1; - } - if (q->bufs[i]->state == VIDEOBUF_ACTIVE) { - dprintk(1, "busy: buffer #%d active\n", i); - return 1; - } - } - return 0; -} -EXPORT_SYMBOL_GPL(videobuf_queue_is_busy); - -/* - * __videobuf_free() - free all the buffers and their control structures - * - * This function can only be called if streaming/reading is off, i.e. no buffers - * are under control of the driver. - */ -/* Locking: Caller holds q->vb_lock */ -static int __videobuf_free(struct videobuf_queue *q) -{ - int i; - - dprintk(1, "%s\n", __func__); - if (!q) - return 0; - - if (q->streaming || q->reading) { - dprintk(1, "Cannot free buffers when streaming or reading\n"); - return -EBUSY; - } - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - for (i = 0; i < VIDEO_MAX_FRAME; i++) - if (q->bufs[i] && q->bufs[i]->map) { - dprintk(1, "Cannot free mmapped buffers\n"); - return -EBUSY; - } - - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - q->ops->buf_release(q, q->bufs[i]); - kfree(q->bufs[i]); - q->bufs[i] = NULL; - } - - return 0; -} - -/* Locking: Caller holds q->vb_lock */ -void videobuf_queue_cancel(struct videobuf_queue *q) -{ - unsigned long flags = 0; - int i; - - q->streaming = 0; - q->reading = 0; - wake_up_interruptible_sync(&q->wait); - - /* remove queued buffers from list */ - spin_lock_irqsave(q->irqlock, flags); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (q->bufs[i]->state == VIDEOBUF_QUEUED) { - list_del(&q->bufs[i]->queue); - q->bufs[i]->state = VIDEOBUF_ERROR; - wake_up_all(&q->bufs[i]->done); - } - } - spin_unlock_irqrestore(q->irqlock, flags); - - /* free all buffers + clear queue */ - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - q->ops->buf_release(q, q->bufs[i]); - } - INIT_LIST_HEAD(&q->stream); -} -EXPORT_SYMBOL_GPL(videobuf_queue_cancel); - -/* --------------------------------------------------------------------- */ - -/* Locking: Caller holds q->vb_lock */ -enum v4l2_field videobuf_next_field(struct videobuf_queue *q) -{ - enum v4l2_field field = q->field; - - BUG_ON(V4L2_FIELD_ANY == field); - - if (V4L2_FIELD_ALTERNATE == field) { - if (V4L2_FIELD_TOP == q->last) { - field = V4L2_FIELD_BOTTOM; - q->last = V4L2_FIELD_BOTTOM; - } else { - field = V4L2_FIELD_TOP; - q->last = V4L2_FIELD_TOP; - } - } - return field; -} -EXPORT_SYMBOL_GPL(videobuf_next_field); - -/* Locking: Caller holds q->vb_lock */ -static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, - struct videobuf_buffer *vb, enum v4l2_buf_type type) -{ - MAGIC_CHECK(vb->magic, MAGIC_BUFFER); - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - b->index = vb->i; - b->type = type; - - b->memory = vb->memory; - switch (b->memory) { - case V4L2_MEMORY_MMAP: - b->m.offset = vb->boff; - b->length = vb->bsize; - break; - case V4L2_MEMORY_USERPTR: - b->m.userptr = vb->baddr; - b->length = vb->bsize; - break; - case V4L2_MEMORY_OVERLAY: - b->m.offset = vb->boff; - break; - case V4L2_MEMORY_DMABUF: - /* DMABUF is not handled in videobuf framework */ - break; - } - - b->flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - if (vb->map) - b->flags |= V4L2_BUF_FLAG_MAPPED; - - switch (vb->state) { - case VIDEOBUF_PREPARED: - case VIDEOBUF_QUEUED: - case VIDEOBUF_ACTIVE: - b->flags |= V4L2_BUF_FLAG_QUEUED; - break; - case VIDEOBUF_ERROR: - b->flags |= V4L2_BUF_FLAG_ERROR; - fallthrough; - case VIDEOBUF_DONE: - b->flags |= V4L2_BUF_FLAG_DONE; - break; - case VIDEOBUF_NEEDS_INIT: - case VIDEOBUF_IDLE: - /* nothing */ - break; - } - - b->field = vb->field; - v4l2_buffer_set_timestamp(b, vb->ts); - b->bytesused = vb->size; - b->sequence = vb->field_count >> 1; -} - -int videobuf_mmap_free(struct videobuf_queue *q) -{ - int ret; - videobuf_queue_lock(q); - ret = __videobuf_free(q); - videobuf_queue_unlock(q); - return ret; -} -EXPORT_SYMBOL_GPL(videobuf_mmap_free); - -/* Locking: Caller holds q->vb_lock */ -int __videobuf_mmap_setup(struct videobuf_queue *q, - unsigned int bcount, unsigned int bsize, - enum v4l2_memory memory) -{ - unsigned int i; - int err; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - err = __videobuf_free(q); - if (0 != err) - return err; - - /* Allocate and initialize buffers */ - for (i = 0; i < bcount; i++) { - q->bufs[i] = videobuf_alloc_vb(q); - - if (NULL == q->bufs[i]) - break; - - q->bufs[i]->i = i; - q->bufs[i]->memory = memory; - q->bufs[i]->bsize = bsize; - switch (memory) { - case V4L2_MEMORY_MMAP: - q->bufs[i]->boff = PAGE_ALIGN(bsize) * i; - break; - case V4L2_MEMORY_USERPTR: - case V4L2_MEMORY_OVERLAY: - case V4L2_MEMORY_DMABUF: - /* nothing */ - break; - } - } - - if (!i) - return -ENOMEM; - - dprintk(1, "mmap setup: %d buffers, %d bytes each\n", i, bsize); - - return i; -} -EXPORT_SYMBOL_GPL(__videobuf_mmap_setup); - -int videobuf_mmap_setup(struct videobuf_queue *q, - unsigned int bcount, unsigned int bsize, - enum v4l2_memory memory) -{ - int ret; - videobuf_queue_lock(q); - ret = __videobuf_mmap_setup(q, bcount, bsize, memory); - videobuf_queue_unlock(q); - return ret; -} -EXPORT_SYMBOL_GPL(videobuf_mmap_setup); - -int videobuf_reqbufs(struct videobuf_queue *q, - struct v4l2_requestbuffers *req) -{ - unsigned int size, count; - int retval; - - if (req->memory != V4L2_MEMORY_MMAP && - req->memory != V4L2_MEMORY_USERPTR && - req->memory != V4L2_MEMORY_OVERLAY) { - dprintk(1, "reqbufs: memory type invalid\n"); - return -EINVAL; - } - - videobuf_queue_lock(q); - if (req->type != q->type) { - dprintk(1, "reqbufs: queue type invalid\n"); - retval = -EINVAL; - goto done; - } - - if (q->streaming) { - dprintk(1, "reqbufs: streaming already exists\n"); - retval = -EBUSY; - goto done; - } - if (!list_empty(&q->stream)) { - dprintk(1, "reqbufs: stream running\n"); - retval = -EBUSY; - goto done; - } - - if (req->count == 0) { - dprintk(1, "reqbufs: count invalid (%d)\n", req->count); - retval = __videobuf_free(q); - goto done; - } - - count = req->count; - if (count > VIDEO_MAX_FRAME) - count = VIDEO_MAX_FRAME; - size = 0; - q->ops->buf_setup(q, &count, &size); - dprintk(1, "reqbufs: bufs=%d, size=0x%x [%u pages total]\n", - count, size, - (unsigned int)((count * PAGE_ALIGN(size)) >> PAGE_SHIFT)); - - retval = __videobuf_mmap_setup(q, count, size, req->memory); - if (retval < 0) { - dprintk(1, "reqbufs: mmap setup returned %d\n", retval); - goto done; - } - - req->count = retval; - retval = 0; - - done: - videobuf_queue_unlock(q); - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_reqbufs); - -int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) -{ - int ret = -EINVAL; - - videobuf_queue_lock(q); - if (unlikely(b->type != q->type)) { - dprintk(1, "querybuf: Wrong type.\n"); - goto done; - } - if (unlikely(b->index >= VIDEO_MAX_FRAME)) { - dprintk(1, "querybuf: index out of range.\n"); - goto done; - } - if (unlikely(NULL == q->bufs[b->index])) { - dprintk(1, "querybuf: buffer is null.\n"); - goto done; - } - - videobuf_status(q, b, q->bufs[b->index], q->type); - - ret = 0; -done: - videobuf_queue_unlock(q); - return ret; -} -EXPORT_SYMBOL_GPL(videobuf_querybuf); - -int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b) -{ - struct videobuf_buffer *buf; - enum v4l2_field field; - unsigned long flags = 0; - int retval; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - if (b->memory == V4L2_MEMORY_MMAP) - mmap_read_lock(current->mm); - - videobuf_queue_lock(q); - retval = -EBUSY; - if (q->reading) { - dprintk(1, "qbuf: Reading running...\n"); - goto done; - } - retval = -EINVAL; - if (b->type != q->type) { - dprintk(1, "qbuf: Wrong type.\n"); - goto done; - } - if (b->index >= VIDEO_MAX_FRAME) { - dprintk(1, "qbuf: index out of range.\n"); - goto done; - } - buf = q->bufs[b->index]; - if (NULL == buf) { - dprintk(1, "qbuf: buffer is null.\n"); - goto done; - } - MAGIC_CHECK(buf->magic, MAGIC_BUFFER); - if (buf->memory != b->memory) { - dprintk(1, "qbuf: memory type is wrong.\n"); - goto done; - } - if (buf->state != VIDEOBUF_NEEDS_INIT && buf->state != VIDEOBUF_IDLE) { - dprintk(1, "qbuf: buffer is already queued or active.\n"); - goto done; - } - - switch (b->memory) { - case V4L2_MEMORY_MMAP: - if (0 == buf->baddr) { - dprintk(1, "qbuf: mmap requested but buffer addr is zero!\n"); - goto done; - } - if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT - || q->type == V4L2_BUF_TYPE_VBI_OUTPUT - || q->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT - || q->type == V4L2_BUF_TYPE_SDR_OUTPUT) { - buf->size = b->bytesused; - buf->field = b->field; - buf->ts = v4l2_buffer_get_timestamp(b); - } - break; - case V4L2_MEMORY_USERPTR: - if (b->length < buf->bsize) { - dprintk(1, "qbuf: buffer length is not enough\n"); - goto done; - } - if (VIDEOBUF_NEEDS_INIT != buf->state && - buf->baddr != b->m.userptr) - q->ops->buf_release(q, buf); - buf->baddr = b->m.userptr; - break; - case V4L2_MEMORY_OVERLAY: - buf->boff = b->m.offset; - break; - default: - dprintk(1, "qbuf: wrong memory type\n"); - goto done; - } - - dprintk(1, "qbuf: requesting next field\n"); - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q, buf, field); - if (0 != retval) { - dprintk(1, "qbuf: buffer_prepare returned %d\n", retval); - goto done; - } - - list_add_tail(&buf->stream, &q->stream); - if (q->streaming) { - spin_lock_irqsave(q->irqlock, flags); - q->ops->buf_queue(q, buf); - spin_unlock_irqrestore(q->irqlock, flags); - } - dprintk(1, "qbuf: succeeded\n"); - retval = 0; - wake_up_interruptible_sync(&q->wait); - -done: - videobuf_queue_unlock(q); - - if (b->memory == V4L2_MEMORY_MMAP) - mmap_read_unlock(current->mm); - - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_qbuf); - -/* Locking: Caller holds q->vb_lock */ -static int stream_next_buffer_check_queue(struct videobuf_queue *q, int noblock) -{ - int retval; - -checks: - if (!q->streaming) { - dprintk(1, "next_buffer: Not streaming\n"); - retval = -EINVAL; - goto done; - } - - if (list_empty(&q->stream)) { - if (noblock) { - retval = -EAGAIN; - dprintk(2, "next_buffer: no buffers to dequeue\n"); - goto done; - } else { - dprintk(2, "next_buffer: waiting on buffer\n"); - - /* Drop lock to avoid deadlock with qbuf */ - videobuf_queue_unlock(q); - - /* Checking list_empty and streaming is safe without - * locks because we goto checks to validate while - * holding locks before proceeding */ - retval = wait_event_interruptible(q->wait, - !list_empty(&q->stream) || !q->streaming); - videobuf_queue_lock(q); - - if (retval) - goto done; - - goto checks; - } - } - - retval = 0; - -done: - return retval; -} - -/* Locking: Caller holds q->vb_lock */ -static int stream_next_buffer(struct videobuf_queue *q, - struct videobuf_buffer **vb, int nonblocking) -{ - int retval; - struct videobuf_buffer *buf = NULL; - - retval = stream_next_buffer_check_queue(q, nonblocking); - if (retval) - goto done; - - buf = list_entry(q->stream.next, struct videobuf_buffer, stream); - retval = videobuf_waiton(q, buf, nonblocking, 1); - if (retval < 0) - goto done; - - *vb = buf; -done: - return retval; -} - -int videobuf_dqbuf(struct videobuf_queue *q, - struct v4l2_buffer *b, int nonblocking) -{ - struct videobuf_buffer *buf = NULL; - int retval; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - memset(b, 0, sizeof(*b)); - videobuf_queue_lock(q); - - retval = stream_next_buffer(q, &buf, nonblocking); - if (retval < 0) { - dprintk(1, "dqbuf: next_buffer error: %i\n", retval); - goto done; - } - - switch (buf->state) { - case VIDEOBUF_ERROR: - dprintk(1, "dqbuf: state is error\n"); - break; - case VIDEOBUF_DONE: - dprintk(1, "dqbuf: state is done\n"); - break; - default: - dprintk(1, "dqbuf: state invalid\n"); - retval = -EINVAL; - goto done; - } - CALL(q, sync, q, buf); - videobuf_status(q, b, buf, q->type); - list_del(&buf->stream); - buf->state = VIDEOBUF_IDLE; - b->flags &= ~V4L2_BUF_FLAG_DONE; -done: - videobuf_queue_unlock(q); - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_dqbuf); - -int videobuf_streamon(struct videobuf_queue *q) -{ - struct videobuf_buffer *buf; - unsigned long flags = 0; - int retval; - - videobuf_queue_lock(q); - retval = -EBUSY; - if (q->reading) - goto done; - retval = 0; - if (q->streaming) - goto done; - q->streaming = 1; - spin_lock_irqsave(q->irqlock, flags); - list_for_each_entry(buf, &q->stream, stream) - if (buf->state == VIDEOBUF_PREPARED) - q->ops->buf_queue(q, buf); - spin_unlock_irqrestore(q->irqlock, flags); - - wake_up_interruptible_sync(&q->wait); -done: - videobuf_queue_unlock(q); - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_streamon); - -/* Locking: Caller holds q->vb_lock */ -static int __videobuf_streamoff(struct videobuf_queue *q) -{ - if (!q->streaming) - return -EINVAL; - - videobuf_queue_cancel(q); - - return 0; -} - -int videobuf_streamoff(struct videobuf_queue *q) -{ - int retval; - - videobuf_queue_lock(q); - retval = __videobuf_streamoff(q); - videobuf_queue_unlock(q); - - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_streamoff); - -/* Locking: Caller holds q->vb_lock */ -static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, - char __user *data, - size_t count, loff_t *ppos) -{ - enum v4l2_field field; - unsigned long flags = 0; - int retval; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - /* setup stuff */ - q->read_buf = videobuf_alloc_vb(q); - if (NULL == q->read_buf) - return -ENOMEM; - - q->read_buf->memory = V4L2_MEMORY_USERPTR; - q->read_buf->baddr = (unsigned long)data; - q->read_buf->bsize = count; - - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q, q->read_buf, field); - if (0 != retval) - goto done; - - /* start capture & wait */ - spin_lock_irqsave(q->irqlock, flags); - q->ops->buf_queue(q, q->read_buf); - spin_unlock_irqrestore(q->irqlock, flags); - retval = videobuf_waiton(q, q->read_buf, 0, 0); - if (0 == retval) { - CALL(q, sync, q, q->read_buf); - if (VIDEOBUF_ERROR == q->read_buf->state) - retval = -EIO; - else - retval = q->read_buf->size; - } - -done: - /* cleanup */ - q->ops->buf_release(q, q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - return retval; -} - -static int __videobuf_copy_to_user(struct videobuf_queue *q, - struct videobuf_buffer *buf, - char __user *data, size_t count, - int nonblocking) -{ - void *vaddr = CALLPTR(q, vaddr, buf); - - /* copy to userspace */ - if (count > buf->size - q->read_off) - count = buf->size - q->read_off; - - if (copy_to_user(data, vaddr + q->read_off, count)) - return -EFAULT; - - return count; -} - -static int __videobuf_copy_stream(struct videobuf_queue *q, - struct videobuf_buffer *buf, - char __user *data, size_t count, size_t pos, - int vbihack, int nonblocking) -{ - unsigned int *fc = CALLPTR(q, vaddr, buf); - - if (vbihack) { - /* dirty, undocumented hack -- pass the frame counter - * within the last four bytes of each vbi data block. - * We need that one to maintain backward compatibility - * to all vbi decoding software out there ... */ - fc += (buf->size >> 2) - 1; - *fc = buf->field_count >> 1; - dprintk(1, "vbihack: %d\n", *fc); - } - - /* copy stuff using the common method */ - count = __videobuf_copy_to_user(q, buf, data, count, nonblocking); - - if ((count == -EFAULT) && (pos == 0)) - return -EFAULT; - - return count; -} - -ssize_t videobuf_read_one(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int nonblocking) -{ - enum v4l2_field field; - unsigned long flags = 0; - unsigned size = 0, nbufs = 1; - int retval; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - videobuf_queue_lock(q); - - q->ops->buf_setup(q, &nbufs, &size); - - if (NULL == q->read_buf && - count >= size && - !nonblocking) { - retval = videobuf_read_zerocopy(q, data, count, ppos); - if (retval >= 0 || retval == -EIO) - /* ok, all done */ - goto done; - /* fallback to kernel bounce buffer on failures */ - } - - if (NULL == q->read_buf) { - /* need to capture a new frame */ - retval = -ENOMEM; - q->read_buf = videobuf_alloc_vb(q); - - dprintk(1, "video alloc=0x%p\n", q->read_buf); - if (NULL == q->read_buf) - goto done; - q->read_buf->memory = V4L2_MEMORY_USERPTR; - q->read_buf->bsize = count; /* preferred size */ - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q, q->read_buf, field); - - if (0 != retval) { - kfree(q->read_buf); - q->read_buf = NULL; - goto done; - } - - spin_lock_irqsave(q->irqlock, flags); - q->ops->buf_queue(q, q->read_buf); - spin_unlock_irqrestore(q->irqlock, flags); - - q->read_off = 0; - } - - /* wait until capture is done */ - retval = videobuf_waiton(q, q->read_buf, nonblocking, 1); - if (0 != retval) - goto done; - - CALL(q, sync, q, q->read_buf); - - if (VIDEOBUF_ERROR == q->read_buf->state) { - /* catch I/O errors */ - q->ops->buf_release(q, q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - retval = -EIO; - goto done; - } - - /* Copy to userspace */ - retval = __videobuf_copy_to_user(q, q->read_buf, data, count, nonblocking); - if (retval < 0) - goto done; - - q->read_off += retval; - if (q->read_off == q->read_buf->size) { - /* all data copied, cleanup */ - q->ops->buf_release(q, q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - } - -done: - videobuf_queue_unlock(q); - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_read_one); - -/* Locking: Caller holds q->vb_lock */ -static int __videobuf_read_start(struct videobuf_queue *q) -{ - enum v4l2_field field; - unsigned long flags = 0; - unsigned int count = 0, size = 0; - int err, i; - - q->ops->buf_setup(q, &count, &size); - if (count < 2) - count = 2; - if (count > VIDEO_MAX_FRAME) - count = VIDEO_MAX_FRAME; - size = PAGE_ALIGN(size); - - err = __videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR); - if (err < 0) - return err; - - count = err; - - for (i = 0; i < count; i++) { - field = videobuf_next_field(q); - err = q->ops->buf_prepare(q, q->bufs[i], field); - if (err) - return err; - list_add_tail(&q->bufs[i]->stream, &q->stream); - } - spin_lock_irqsave(q->irqlock, flags); - for (i = 0; i < count; i++) - q->ops->buf_queue(q, q->bufs[i]); - spin_unlock_irqrestore(q->irqlock, flags); - q->reading = 1; - return 0; -} - -static void __videobuf_read_stop(struct videobuf_queue *q) -{ - int i; - - videobuf_queue_cancel(q); - __videobuf_free(q); - INIT_LIST_HEAD(&q->stream); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - kfree(q->bufs[i]); - q->bufs[i] = NULL; - } - q->read_buf = NULL; -} - -int videobuf_read_start(struct videobuf_queue *q) -{ - int rc; - - videobuf_queue_lock(q); - rc = __videobuf_read_start(q); - videobuf_queue_unlock(q); - - return rc; -} -EXPORT_SYMBOL_GPL(videobuf_read_start); - -void videobuf_read_stop(struct videobuf_queue *q) -{ - videobuf_queue_lock(q); - __videobuf_read_stop(q); - videobuf_queue_unlock(q); -} -EXPORT_SYMBOL_GPL(videobuf_read_stop); - -void videobuf_stop(struct videobuf_queue *q) -{ - videobuf_queue_lock(q); - - if (q->streaming) - __videobuf_streamoff(q); - - if (q->reading) - __videobuf_read_stop(q); - - videobuf_queue_unlock(q); -} -EXPORT_SYMBOL_GPL(videobuf_stop); - -ssize_t videobuf_read_stream(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int vbihack, int nonblocking) -{ - int rc, retval; - unsigned long flags = 0; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - dprintk(2, "%s\n", __func__); - videobuf_queue_lock(q); - retval = -EBUSY; - if (q->streaming) - goto done; - if (!q->reading) { - retval = __videobuf_read_start(q); - if (retval < 0) - goto done; - } - - retval = 0; - while (count > 0) { - /* get / wait for data */ - if (NULL == q->read_buf) { - q->read_buf = list_entry(q->stream.next, - struct videobuf_buffer, - stream); - list_del(&q->read_buf->stream); - q->read_off = 0; - } - rc = videobuf_waiton(q, q->read_buf, nonblocking, 1); - if (rc < 0) { - if (0 == retval) - retval = rc; - break; - } - - if (q->read_buf->state == VIDEOBUF_DONE) { - rc = __videobuf_copy_stream(q, q->read_buf, data + retval, count, - retval, vbihack, nonblocking); - if (rc < 0) { - retval = rc; - break; - } - retval += rc; - count -= rc; - q->read_off += rc; - } else { - /* some error */ - q->read_off = q->read_buf->size; - if (0 == retval) - retval = -EIO; - } - - /* requeue buffer when done with copying */ - if (q->read_off == q->read_buf->size) { - list_add_tail(&q->read_buf->stream, - &q->stream); - spin_lock_irqsave(q->irqlock, flags); - q->ops->buf_queue(q, q->read_buf); - spin_unlock_irqrestore(q->irqlock, flags); - q->read_buf = NULL; - } - if (retval < 0) - break; - } - -done: - videobuf_queue_unlock(q); - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_read_stream); - -__poll_t videobuf_poll_stream(struct file *file, - struct videobuf_queue *q, - poll_table *wait) -{ - __poll_t req_events = poll_requested_events(wait); - struct videobuf_buffer *buf = NULL; - __poll_t rc = 0; - - videobuf_queue_lock(q); - if (q->streaming) { - if (!list_empty(&q->stream)) - buf = list_entry(q->stream.next, - struct videobuf_buffer, stream); - } else if (req_events & (EPOLLIN | EPOLLRDNORM)) { - if (!q->reading) - __videobuf_read_start(q); - if (!q->reading) { - rc = EPOLLERR; - } else if (NULL == q->read_buf) { - q->read_buf = list_entry(q->stream.next, - struct videobuf_buffer, - stream); - list_del(&q->read_buf->stream); - q->read_off = 0; - } - buf = q->read_buf; - } - if (buf) - poll_wait(file, &buf->done, wait); - else - rc = EPOLLERR; - - if (0 == rc) { - if (buf->state == VIDEOBUF_DONE || - buf->state == VIDEOBUF_ERROR) { - switch (q->type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - case V4L2_BUF_TYPE_VBI_OUTPUT: - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - case V4L2_BUF_TYPE_SDR_OUTPUT: - rc = EPOLLOUT | EPOLLWRNORM; - break; - default: - rc = EPOLLIN | EPOLLRDNORM; - break; - } - } - } - videobuf_queue_unlock(q); - return rc; -} -EXPORT_SYMBOL_GPL(videobuf_poll_stream); - -int videobuf_mmap_mapper(struct videobuf_queue *q, struct vm_area_struct *vma) -{ - int rc = -EINVAL; - int i; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) { - dprintk(1, "mmap appl bug: PROT_WRITE and MAP_SHARED are required\n"); - return -EINVAL; - } - - videobuf_queue_lock(q); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - struct videobuf_buffer *buf = q->bufs[i]; - - if (buf && buf->memory == V4L2_MEMORY_MMAP && - buf->boff == (vma->vm_pgoff << PAGE_SHIFT)) { - rc = CALL(q, mmap_mapper, q, buf, vma); - break; - } - } - videobuf_queue_unlock(q); - - return rc; -} -EXPORT_SYMBOL_GPL(videobuf_mmap_mapper); diff --git a/drivers/media/v4l2-core/videobuf-dma-contig.c b/drivers/media/v4l2-core/videobuf-dma-contig.c deleted file mode 100644 index 4c2ec7a0d804a..0000000000000 --- a/drivers/media/v4l2-core/videobuf-dma-contig.c +++ /dev/null @@ -1,402 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * helper functions for physically contiguous capture buffers - * - * The functions support hardware lacking scatter gather support - * (i.e. the buffers must be linear in physical memory) - * - * Copyright (c) 2008 Magnus Damm - * - * Based on videobuf-vmalloc.c, - * (c) 2007 Mauro Carvalho Chehab, - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -struct videobuf_dma_contig_memory { - u32 magic; - void *vaddr; - dma_addr_t dma_handle; - unsigned long size; -}; - -#define MAGIC_DC_MEM 0x0733ac61 -#define MAGIC_CHECK(is, should) \ - if (unlikely((is) != (should))) { \ - pr_err("magic mismatch: %x expected %x\n", (is), (should)); \ - BUG(); \ - } - -static int __videobuf_dc_alloc(struct device *dev, - struct videobuf_dma_contig_memory *mem, - unsigned long size) -{ - mem->size = size; - mem->vaddr = dma_alloc_coherent(dev, mem->size, &mem->dma_handle, - GFP_KERNEL); - if (!mem->vaddr) { - dev_err(dev, "memory alloc size %ld failed\n", mem->size); - return -ENOMEM; - } - - dev_dbg(dev, "dma mapped data is at %p (%ld)\n", mem->vaddr, mem->size); - - return 0; -} - -static void __videobuf_dc_free(struct device *dev, - struct videobuf_dma_contig_memory *mem) -{ - dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle); - - mem->vaddr = NULL; -} - -static void videobuf_vm_open(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - - dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", - map, map->count, vma->vm_start, vma->vm_end); - - map->count++; -} - -static void videobuf_vm_close(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - struct videobuf_queue *q = map->q; - int i; - - dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", - map, map->count, vma->vm_start, vma->vm_end); - - map->count--; - if (0 == map->count) { - struct videobuf_dma_contig_memory *mem; - - dev_dbg(q->dev, "munmap %p q=%p\n", map, q); - videobuf_queue_lock(q); - - /* We need first to cancel streams, before unmapping */ - if (q->streaming) - videobuf_queue_cancel(q); - - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - - if (q->bufs[i]->map != map) - continue; - - mem = q->bufs[i]->priv; - if (mem) { - /* This callback is called only if kernel has - allocated memory and this memory is mmapped. - In this case, memory should be freed, - in order to do memory unmap. - */ - - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - /* vfree is not atomic - can't be - called with IRQ's disabled - */ - dev_dbg(q->dev, "buf[%d] freeing %p\n", - i, mem->vaddr); - - __videobuf_dc_free(q->dev, mem); - mem->vaddr = NULL; - } - - q->bufs[i]->map = NULL; - q->bufs[i]->baddr = 0; - } - - kfree(map); - - videobuf_queue_unlock(q); - } -} - -static const struct vm_operations_struct videobuf_vm_ops = { - .open = videobuf_vm_open, - .close = videobuf_vm_close, -}; - -/** - * videobuf_dma_contig_user_put() - reset pointer to user space buffer - * @mem: per-buffer private videobuf-dma-contig data - * - * This function resets the user space pointer - */ -static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem) -{ - mem->dma_handle = 0; - mem->size = 0; -} - -/** - * videobuf_dma_contig_user_get() - setup user space memory pointer - * @mem: per-buffer private videobuf-dma-contig data - * @vb: video buffer to map - * - * This function validates and sets up a pointer to user space memory. - * Only physically contiguous pfn-mapped memory is accepted. - * - * Returns 0 if successful. - */ -static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem, - struct videobuf_buffer *vb) -{ - unsigned long untagged_baddr = untagged_addr(vb->baddr); - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - unsigned long prev_pfn, this_pfn; - unsigned long pages_done, user_address; - unsigned int offset; - int ret; - - offset = untagged_baddr & ~PAGE_MASK; - mem->size = PAGE_ALIGN(vb->size + offset); - ret = -EINVAL; - - mmap_read_lock(mm); - - vma = find_vma(mm, untagged_baddr); - if (!vma) - goto out_up; - - if ((untagged_baddr + mem->size) > vma->vm_end) - goto out_up; - - pages_done = 0; - prev_pfn = 0; /* kill warning */ - user_address = untagged_baddr; - - while (pages_done < (mem->size >> PAGE_SHIFT)) { - ret = follow_pfn(vma, user_address, &this_pfn); - if (ret) - break; - - if (pages_done == 0) - mem->dma_handle = (this_pfn << PAGE_SHIFT) + offset; - else if (this_pfn != (prev_pfn + 1)) - ret = -EFAULT; - - if (ret) - break; - - prev_pfn = this_pfn; - user_address += PAGE_SIZE; - pages_done++; - } - -out_up: - mmap_read_unlock(current->mm); - - return ret; -} - -static struct videobuf_buffer *__videobuf_alloc(size_t size) -{ - struct videobuf_dma_contig_memory *mem; - struct videobuf_buffer *vb; - - vb = kzalloc(size + sizeof(*mem), GFP_KERNEL); - if (vb) { - vb->priv = ((char *)vb) + size; - mem = vb->priv; - mem->magic = MAGIC_DC_MEM; - } - - return vb; -} - -static void *__videobuf_to_vaddr(struct videobuf_buffer *buf) -{ - struct videobuf_dma_contig_memory *mem = buf->priv; - - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - return mem->vaddr; -} - -static int __videobuf_iolock(struct videobuf_queue *q, - struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf) -{ - struct videobuf_dma_contig_memory *mem = vb->priv; - - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - switch (vb->memory) { - case V4L2_MEMORY_MMAP: - dev_dbg(q->dev, "%s memory method MMAP\n", __func__); - - /* All handling should be done by __videobuf_mmap_mapper() */ - if (!mem->vaddr) { - dev_err(q->dev, "memory is not allocated/mmapped.\n"); - return -EINVAL; - } - break; - case V4L2_MEMORY_USERPTR: - dev_dbg(q->dev, "%s memory method USERPTR\n", __func__); - - /* handle pointer from user space */ - if (vb->baddr) - return videobuf_dma_contig_user_get(mem, vb); - - /* allocate memory for the read() method */ - if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(vb->size))) - return -ENOMEM; - break; - case V4L2_MEMORY_OVERLAY: - default: - dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n", __func__); - return -EINVAL; - } - - return 0; -} - -static int __videobuf_mmap_mapper(struct videobuf_queue *q, - struct videobuf_buffer *buf, - struct vm_area_struct *vma) -{ - struct videobuf_dma_contig_memory *mem; - struct videobuf_mapping *map; - int retval; - - dev_dbg(q->dev, "%s\n", __func__); - - /* create mapping + update buffer list */ - map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); - if (!map) - return -ENOMEM; - - buf->map = map; - map->q = q; - - buf->baddr = vma->vm_start; - - mem = buf->priv; - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(buf->bsize))) - goto error; - - /* the "vm_pgoff" is just used in v4l2 to find the - * corresponding buffer data structure which is allocated - * earlier and it does not mean the offset from the physical - * buffer start address as usual. So set it to 0 to pass - * the sanity check in dma_mmap_coherent(). - */ - vma->vm_pgoff = 0; - retval = dma_mmap_coherent(q->dev, vma, mem->vaddr, mem->dma_handle, - mem->size); - if (retval) { - dev_err(q->dev, "mmap: remap failed with error %d. ", - retval); - dma_free_coherent(q->dev, mem->size, - mem->vaddr, mem->dma_handle); - goto error; - } - - vma->vm_ops = &videobuf_vm_ops; - vm_flags_set(vma, VM_DONTEXPAND); - vma->vm_private_data = map; - - dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", - map, q, vma->vm_start, vma->vm_end, - (long int)buf->bsize, vma->vm_pgoff, buf->i); - - videobuf_vm_open(vma); - - return 0; - -error: - kfree(map); - return -ENOMEM; -} - -static struct videobuf_qtype_ops qops = { - .magic = MAGIC_QTYPE_OPS, - .alloc_vb = __videobuf_alloc, - .iolock = __videobuf_iolock, - .mmap_mapper = __videobuf_mmap_mapper, - .vaddr = __videobuf_to_vaddr, -}; - -void videobuf_queue_dma_contig_init(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct mutex *ext_lock) -{ - videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, - priv, &qops, ext_lock); -} -EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init); - -dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf) -{ - struct videobuf_dma_contig_memory *mem = buf->priv; - - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - return mem->dma_handle; -} -EXPORT_SYMBOL_GPL(videobuf_to_dma_contig); - -void videobuf_dma_contig_free(struct videobuf_queue *q, - struct videobuf_buffer *buf) -{ - struct videobuf_dma_contig_memory *mem = buf->priv; - - /* mmapped memory can't be freed here, otherwise mmapped region - would be released, while still needed. In this case, the memory - release should happen inside videobuf_vm_close(). - So, it should free memory only if the memory were allocated for - read() operation. - */ - if (buf->memory != V4L2_MEMORY_USERPTR) - return; - - if (!mem) - return; - - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - /* handle user space pointer case */ - if (buf->baddr) { - videobuf_dma_contig_user_put(mem); - return; - } - - /* read() method */ - if (mem->vaddr) { - __videobuf_dc_free(q->dev, mem); - mem->vaddr = NULL; - } -} -EXPORT_SYMBOL_GPL(videobuf_dma_contig_free); - -MODULE_DESCRIPTION("helper module to manage video4linux dma contig buffers"); -MODULE_AUTHOR("Magnus Damm"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c deleted file mode 100644 index 405b89ea1054d..0000000000000 --- a/drivers/media/v4l2-core/videobuf-dma-sg.c +++ /dev/null @@ -1,681 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * helper functions for SG DMA video4linux capture buffers - * - * The functions expect the hardware being able to scatter gather - * (i.e. the buffers are not linear in physical memory, but fragmented - * into PAGE_SIZE chunks). They also assume the driver does not need - * to touch the video data. - * - * (c) 2007 Mauro Carvalho Chehab, - * - * Highly based on video-buf written originally by: - * (c) 2001,02 Gerd Knorr - * (c) 2006 Mauro Carvalho Chehab, - * (c) 2006 Ted Walther and John Sokol - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#define MAGIC_DMABUF 0x19721112 -#define MAGIC_SG_MEM 0x17890714 - -#define MAGIC_CHECK(is, should) \ - if (unlikely((is) != (should))) { \ - printk(KERN_ERR "magic mismatch: %x (expected %x)\n", \ - is, should); \ - BUG(); \ - } - -static int debug; -module_param(debug, int, 0644); - -MODULE_DESCRIPTION("helper module to manage video4linux dma sg buffers"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); - -#define dprintk(level, fmt, arg...) \ - if (debug >= level) \ - printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg) - -/* --------------------------------------------------------------------- */ - -/* - * Return a scatterlist for some page-aligned vmalloc()'ed memory - * block (NULL on errors). Memory for the scatterlist is allocated - * using kmalloc. The caller must free the memory. - */ -static struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt, - int nr_pages) -{ - struct scatterlist *sglist; - struct page *pg; - int i; - - sglist = vzalloc(array_size(nr_pages, sizeof(*sglist))); - if (NULL == sglist) - return NULL; - sg_init_table(sglist, nr_pages); - for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { - pg = vmalloc_to_page(virt); - if (NULL == pg) - goto err; - BUG_ON(PageHighMem(pg)); - sg_set_page(&sglist[i], pg, PAGE_SIZE, 0); - } - return sglist; - -err: - vfree(sglist); - return NULL; -} - -/* - * Return a scatterlist for a an array of userpages (NULL on errors). - * Memory for the scatterlist is allocated using kmalloc. The caller - * must free the memory. - */ -static struct scatterlist *videobuf_pages_to_sg(struct page **pages, - int nr_pages, int offset, size_t size) -{ - struct scatterlist *sglist; - int i; - - if (NULL == pages[0]) - return NULL; - sglist = vmalloc(array_size(nr_pages, sizeof(*sglist))); - if (NULL == sglist) - return NULL; - sg_init_table(sglist, nr_pages); - - if (PageHighMem(pages[0])) - /* DMA to highmem pages might not work */ - goto highmem; - sg_set_page(&sglist[0], pages[0], - min_t(size_t, PAGE_SIZE - offset, size), offset); - size -= min_t(size_t, PAGE_SIZE - offset, size); - for (i = 1; i < nr_pages; i++) { - if (NULL == pages[i]) - goto nopage; - if (PageHighMem(pages[i])) - goto highmem; - sg_set_page(&sglist[i], pages[i], min_t(size_t, PAGE_SIZE, size), 0); - size -= min_t(size_t, PAGE_SIZE, size); - } - return sglist; - -nopage: - dprintk(2, "sgl: oops - no page\n"); - vfree(sglist); - return NULL; - -highmem: - dprintk(2, "sgl: oops - highmem page\n"); - vfree(sglist); - return NULL; -} - -/* --------------------------------------------------------------------- */ - -struct videobuf_dmabuf *videobuf_to_dma(struct videobuf_buffer *buf) -{ - struct videobuf_dma_sg_memory *mem = buf->priv; - BUG_ON(!mem); - - MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); - - return &mem->dma; -} -EXPORT_SYMBOL_GPL(videobuf_to_dma); - -static void videobuf_dma_init(struct videobuf_dmabuf *dma) -{ - memset(dma, 0, sizeof(*dma)); - dma->magic = MAGIC_DMABUF; -} - -static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma, - int direction, unsigned long data, unsigned long size) -{ - unsigned int gup_flags = FOLL_LONGTERM; - unsigned long first, last; - int err; - - dma->direction = direction; - switch (dma->direction) { - case DMA_FROM_DEVICE: - gup_flags |= FOLL_WRITE; - break; - case DMA_TO_DEVICE: - break; - default: - BUG(); - } - - first = (data & PAGE_MASK) >> PAGE_SHIFT; - last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT; - dma->offset = data & ~PAGE_MASK; - dma->size = size; - dma->nr_pages = last-first+1; - dma->pages = kmalloc_array(dma->nr_pages, sizeof(struct page *), - GFP_KERNEL); - if (NULL == dma->pages) - return -ENOMEM; - - dprintk(1, "init user [0x%lx+0x%lx => %lu pages]\n", - data, size, dma->nr_pages); - - err = pin_user_pages(data & PAGE_MASK, dma->nr_pages, gup_flags, - dma->pages); - - if (err != dma->nr_pages) { - dma->nr_pages = (err >= 0) ? err : 0; - dprintk(1, "pin_user_pages: err=%d [%lu]\n", err, - dma->nr_pages); - return err < 0 ? err : -EINVAL; - } - return 0; -} - -static int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, - unsigned long data, unsigned long size) -{ - int ret; - - mmap_read_lock(current->mm); - ret = videobuf_dma_init_user_locked(dma, direction, data, size); - mmap_read_unlock(current->mm); - - return ret; -} - -static int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, - unsigned long nr_pages) -{ - int i; - - dprintk(1, "init kernel [%lu pages]\n", nr_pages); - - dma->direction = direction; - dma->vaddr_pages = kcalloc(nr_pages, sizeof(*dma->vaddr_pages), - GFP_KERNEL); - if (!dma->vaddr_pages) - return -ENOMEM; - - dma->dma_addr = kcalloc(nr_pages, sizeof(*dma->dma_addr), GFP_KERNEL); - if (!dma->dma_addr) { - kfree(dma->vaddr_pages); - return -ENOMEM; - } - for (i = 0; i < nr_pages; i++) { - void *addr; - - addr = dma_alloc_coherent(dma->dev, PAGE_SIZE, - &(dma->dma_addr[i]), GFP_KERNEL); - if (addr == NULL) - goto out_free_pages; - - dma->vaddr_pages[i] = virt_to_page(addr); - } - dma->vaddr = vmap(dma->vaddr_pages, nr_pages, VM_MAP | VM_IOREMAP, - PAGE_KERNEL); - if (NULL == dma->vaddr) { - dprintk(1, "vmalloc_32(%lu pages) failed\n", nr_pages); - goto out_free_pages; - } - - dprintk(1, "vmalloc is at addr %p, size=%lu\n", - dma->vaddr, nr_pages << PAGE_SHIFT); - - memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT); - dma->nr_pages = nr_pages; - - return 0; -out_free_pages: - while (i > 0) { - void *addr; - - i--; - addr = page_address(dma->vaddr_pages[i]); - dma_free_coherent(dma->dev, PAGE_SIZE, addr, dma->dma_addr[i]); - } - kfree(dma->dma_addr); - dma->dma_addr = NULL; - kfree(dma->vaddr_pages); - dma->vaddr_pages = NULL; - - return -ENOMEM; - -} - -static int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, - dma_addr_t addr, unsigned long nr_pages) -{ - dprintk(1, "init overlay [%lu pages @ bus 0x%lx]\n", - nr_pages, (unsigned long)addr); - dma->direction = direction; - - if (0 == addr) - return -EINVAL; - - dma->bus_addr = addr; - dma->nr_pages = nr_pages; - - return 0; -} - -static int videobuf_dma_map(struct device *dev, struct videobuf_dmabuf *dma) -{ - MAGIC_CHECK(dma->magic, MAGIC_DMABUF); - BUG_ON(0 == dma->nr_pages); - - if (dma->pages) { - dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages, - dma->offset, dma->size); - } - if (dma->vaddr) { - dma->sglist = videobuf_vmalloc_to_sg(dma->vaddr, - dma->nr_pages); - } - if (dma->bus_addr) { - dma->sglist = vmalloc(sizeof(*dma->sglist)); - if (NULL != dma->sglist) { - dma->sglen = 1; - sg_dma_address(&dma->sglist[0]) = dma->bus_addr - & PAGE_MASK; - dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK; - sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE; - } - } - if (NULL == dma->sglist) { - dprintk(1, "scatterlist is NULL\n"); - return -ENOMEM; - } - if (!dma->bus_addr) { - dma->sglen = dma_map_sg(dev, dma->sglist, - dma->nr_pages, dma->direction); - if (0 == dma->sglen) { - printk(KERN_WARNING - "%s: videobuf_map_sg failed\n", __func__); - vfree(dma->sglist); - dma->sglist = NULL; - dma->sglen = 0; - return -ENOMEM; - } - } - - return 0; -} - -int videobuf_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma) -{ - MAGIC_CHECK(dma->magic, MAGIC_DMABUF); - - if (!dma->sglen) - return 0; - - dma_unmap_sg(dev, dma->sglist, dma->nr_pages, dma->direction); - - vfree(dma->sglist); - dma->sglist = NULL; - dma->sglen = 0; - - return 0; -} -EXPORT_SYMBOL_GPL(videobuf_dma_unmap); - -int videobuf_dma_free(struct videobuf_dmabuf *dma) -{ - int i; - MAGIC_CHECK(dma->magic, MAGIC_DMABUF); - BUG_ON(dma->sglen); - - if (dma->pages) { - unpin_user_pages_dirty_lock(dma->pages, dma->nr_pages, - dma->direction == DMA_FROM_DEVICE); - kfree(dma->pages); - dma->pages = NULL; - } - - if (dma->dma_addr) { - for (i = 0; i < dma->nr_pages; i++) { - void *addr; - - addr = page_address(dma->vaddr_pages[i]); - dma_free_coherent(dma->dev, PAGE_SIZE, addr, - dma->dma_addr[i]); - } - kfree(dma->dma_addr); - dma->dma_addr = NULL; - kfree(dma->vaddr_pages); - dma->vaddr_pages = NULL; - vunmap(dma->vaddr); - dma->vaddr = NULL; - } - - if (dma->bus_addr) - dma->bus_addr = 0; - dma->direction = DMA_NONE; - - return 0; -} -EXPORT_SYMBOL_GPL(videobuf_dma_free); - -/* --------------------------------------------------------------------- */ - -static void videobuf_vm_open(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - - dprintk(2, "vm_open %p [count=%d,vma=%08lx-%08lx]\n", map, - map->count, vma->vm_start, vma->vm_end); - - map->count++; -} - -static void videobuf_vm_close(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - struct videobuf_queue *q = map->q; - struct videobuf_dma_sg_memory *mem; - int i; - - dprintk(2, "vm_close %p [count=%d,vma=%08lx-%08lx]\n", map, - map->count, vma->vm_start, vma->vm_end); - - map->count--; - if (0 == map->count) { - dprintk(1, "munmap %p q=%p\n", map, q); - videobuf_queue_lock(q); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - mem = q->bufs[i]->priv; - if (!mem) - continue; - - MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); - - if (q->bufs[i]->map != map) - continue; - q->bufs[i]->map = NULL; - q->bufs[i]->baddr = 0; - q->ops->buf_release(q, q->bufs[i]); - } - videobuf_queue_unlock(q); - kfree(map); - } -} - -/* - * Get a anonymous page for the mapping. Make sure we can DMA to that - * memory location with 32bit PCI devices (i.e. don't use highmem for - * now ...). Bounce buffers don't work very well for the data rates - * video capture has. - */ -static vm_fault_t videobuf_vm_fault(struct vm_fault *vmf) -{ - struct vm_area_struct *vma = vmf->vma; - struct page *page; - - dprintk(3, "fault: fault @ %08lx [vma %08lx-%08lx]\n", - vmf->address, vma->vm_start, vma->vm_end); - - page = alloc_page(GFP_USER | __GFP_DMA32); - if (!page) - return VM_FAULT_OOM; - clear_user_highpage(page, vmf->address); - vmf->page = page; - - return 0; -} - -static const struct vm_operations_struct videobuf_vm_ops = { - .open = videobuf_vm_open, - .close = videobuf_vm_close, - .fault = videobuf_vm_fault, -}; - -/* --------------------------------------------------------------------- - * SG handlers for the generic methods - */ - -/* Allocated area consists on 3 parts: - struct video_buffer - struct _buffer (cx88_buffer, saa7134_buf, ...) - struct videobuf_dma_sg_memory - */ - -static struct videobuf_buffer *__videobuf_alloc_vb(size_t size) -{ - struct videobuf_dma_sg_memory *mem; - struct videobuf_buffer *vb; - - vb = kzalloc(size + sizeof(*mem), GFP_KERNEL); - if (!vb) - return vb; - - mem = vb->priv = ((char *)vb) + size; - mem->magic = MAGIC_SG_MEM; - - videobuf_dma_init(&mem->dma); - - dprintk(1, "%s: allocated at %p(%ld+%ld) & %p(%ld)\n", - __func__, vb, (long)sizeof(*vb), (long)size - sizeof(*vb), - mem, (long)sizeof(*mem)); - - return vb; -} - -static void *__videobuf_to_vaddr(struct videobuf_buffer *buf) -{ - struct videobuf_dma_sg_memory *mem = buf->priv; - BUG_ON(!mem); - - MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); - - return mem->dma.vaddr; -} - -static int __videobuf_iolock(struct videobuf_queue *q, - struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf) -{ - struct videobuf_dma_sg_memory *mem = vb->priv; - unsigned long pages; - dma_addr_t bus; - int err; - - BUG_ON(!mem); - - MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); - - if (!mem->dma.dev) - mem->dma.dev = q->dev; - else - WARN_ON(mem->dma.dev != q->dev); - - switch (vb->memory) { - case V4L2_MEMORY_MMAP: - case V4L2_MEMORY_USERPTR: - if (0 == vb->baddr) { - /* no userspace addr -- kernel bounce buffer */ - pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; - err = videobuf_dma_init_kernel(&mem->dma, - DMA_FROM_DEVICE, - pages); - if (0 != err) - return err; - } else if (vb->memory == V4L2_MEMORY_USERPTR) { - /* dma directly to userspace */ - err = videobuf_dma_init_user(&mem->dma, - DMA_FROM_DEVICE, - vb->baddr, vb->bsize); - if (0 != err) - return err; - } else { - /* NOTE: HACK: videobuf_iolock on V4L2_MEMORY_MMAP - buffers can only be called from videobuf_qbuf - we take current->mm->mmap_lock there, to prevent - locking inversion, so don't take it here */ - - err = videobuf_dma_init_user_locked(&mem->dma, - DMA_FROM_DEVICE, - vb->baddr, vb->bsize); - if (0 != err) - return err; - } - break; - case V4L2_MEMORY_OVERLAY: - if (NULL == fbuf) - return -EINVAL; - /* FIXME: need sanity checks for vb->boff */ - /* - * Using a double cast to avoid compiler warnings when - * building for PAE. Compiler doesn't like direct casting - * of a 32 bit ptr to 64 bit integer. - */ - bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff; - pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; - err = videobuf_dma_init_overlay(&mem->dma, DMA_FROM_DEVICE, - bus, pages); - if (0 != err) - return err; - break; - default: - BUG(); - } - err = videobuf_dma_map(q->dev, &mem->dma); - if (0 != err) - return err; - - return 0; -} - -static int __videobuf_sync(struct videobuf_queue *q, - struct videobuf_buffer *buf) -{ - struct videobuf_dma_sg_memory *mem = buf->priv; - BUG_ON(!mem || !mem->dma.sglen); - - MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); - MAGIC_CHECK(mem->dma.magic, MAGIC_DMABUF); - - dma_sync_sg_for_cpu(q->dev, mem->dma.sglist, - mem->dma.nr_pages, mem->dma.direction); - - return 0; -} - -static int __videobuf_mmap_mapper(struct videobuf_queue *q, - struct videobuf_buffer *buf, - struct vm_area_struct *vma) -{ - struct videobuf_dma_sg_memory *mem = buf->priv; - struct videobuf_mapping *map; - unsigned int first, last, size = 0, i; - int retval; - - retval = -EINVAL; - - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); - - /* look for first buffer to map */ - for (first = 0; first < VIDEO_MAX_FRAME; first++) { - if (buf == q->bufs[first]) { - size = PAGE_ALIGN(q->bufs[first]->bsize); - break; - } - } - - /* paranoia, should never happen since buf is always valid. */ - if (!size) { - dprintk(1, "mmap app bug: offset invalid [offset=0x%lx]\n", - (vma->vm_pgoff << PAGE_SHIFT)); - goto done; - } - - last = first; - - /* create mapping + update buffer list */ - retval = -ENOMEM; - map = kmalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); - if (NULL == map) - goto done; - - size = 0; - for (i = first; i <= last; i++) { - if (NULL == q->bufs[i]) - continue; - q->bufs[i]->map = map; - q->bufs[i]->baddr = vma->vm_start + size; - size += PAGE_ALIGN(q->bufs[i]->bsize); - } - - map->count = 1; - map->q = q; - vma->vm_ops = &videobuf_vm_ops; - /* using shared anonymous pages */ - vm_flags_mod(vma, VM_DONTEXPAND | VM_DONTDUMP, VM_IO); - vma->vm_private_data = map; - dprintk(1, "mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n", - map, q, vma->vm_start, vma->vm_end, vma->vm_pgoff, first, last); - retval = 0; - -done: - return retval; -} - -static struct videobuf_qtype_ops sg_ops = { - .magic = MAGIC_QTYPE_OPS, - - .alloc_vb = __videobuf_alloc_vb, - .iolock = __videobuf_iolock, - .sync = __videobuf_sync, - .mmap_mapper = __videobuf_mmap_mapper, - .vaddr = __videobuf_to_vaddr, -}; - -void *videobuf_sg_alloc(size_t size) -{ - struct videobuf_queue q; - - /* Required to make generic handler to call __videobuf_alloc */ - q.int_ops = &sg_ops; - - q.msize = size; - - return videobuf_alloc_vb(&q); -} -EXPORT_SYMBOL_GPL(videobuf_sg_alloc); - -void videobuf_queue_sg_init(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct mutex *ext_lock) -{ - videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, - priv, &sg_ops, ext_lock); -} -EXPORT_SYMBOL_GPL(videobuf_queue_sg_init); - diff --git a/drivers/media/v4l2-core/videobuf-vmalloc.c b/drivers/media/v4l2-core/videobuf-vmalloc.c deleted file mode 100644 index 85c7090606d60..0000000000000 --- a/drivers/media/v4l2-core/videobuf-vmalloc.c +++ /dev/null @@ -1,326 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * helper functions for vmalloc video4linux capture buffers - * - * The functions expect the hardware being able to scatter gather - * (i.e. the buffers are not linear in physical memory, but fragmented - * into PAGE_SIZE chunks). They also assume the driver does not need - * to touch the video data. - * - * (c) 2007 Mauro Carvalho Chehab - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#define MAGIC_DMABUF 0x17760309 -#define MAGIC_VMAL_MEM 0x18221223 - -#define MAGIC_CHECK(is, should) \ - if (unlikely((is) != (should))) { \ - printk(KERN_ERR "magic mismatch: %x (expected %x)\n", \ - is, should); \ - BUG(); \ - } - -static int debug; -module_param(debug, int, 0644); - -MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); - -#define dprintk(level, fmt, arg...) \ - if (debug >= level) \ - printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg) - - -/***************************************************************************/ - -static void videobuf_vm_open(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - - dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map, - map->count, vma->vm_start, vma->vm_end); - - map->count++; -} - -static void videobuf_vm_close(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - struct videobuf_queue *q = map->q; - int i; - - dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map, - map->count, vma->vm_start, vma->vm_end); - - map->count--; - if (0 == map->count) { - struct videobuf_vmalloc_memory *mem; - - dprintk(1, "munmap %p q=%p\n", map, q); - videobuf_queue_lock(q); - - /* We need first to cancel streams, before unmapping */ - if (q->streaming) - videobuf_queue_cancel(q); - - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - - if (q->bufs[i]->map != map) - continue; - - mem = q->bufs[i]->priv; - if (mem) { - /* This callback is called only if kernel has - allocated memory and this memory is mmapped. - In this case, memory should be freed, - in order to do memory unmap. - */ - - MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); - - /* vfree is not atomic - can't be - called with IRQ's disabled - */ - dprintk(1, "%s: buf[%d] freeing (%p)\n", - __func__, i, mem->vaddr); - - vfree(mem->vaddr); - mem->vaddr = NULL; - } - - q->bufs[i]->map = NULL; - q->bufs[i]->baddr = 0; - } - - kfree(map); - - videobuf_queue_unlock(q); - } - - return; -} - -static const struct vm_operations_struct videobuf_vm_ops = { - .open = videobuf_vm_open, - .close = videobuf_vm_close, -}; - -/* --------------------------------------------------------------------- - * vmalloc handlers for the generic methods - */ - -/* Allocated area consists on 3 parts: - struct video_buffer - struct _buffer (cx88_buffer, saa7134_buf, ...) - struct videobuf_dma_sg_memory - */ - -static struct videobuf_buffer *__videobuf_alloc_vb(size_t size) -{ - struct videobuf_vmalloc_memory *mem; - struct videobuf_buffer *vb; - - vb = kzalloc(size + sizeof(*mem), GFP_KERNEL); - if (!vb) - return vb; - - mem = vb->priv = ((char *)vb) + size; - mem->magic = MAGIC_VMAL_MEM; - - dprintk(1, "%s: allocated at %p(%ld+%ld) & %p(%ld)\n", - __func__, vb, (long)sizeof(*vb), (long)size - sizeof(*vb), - mem, (long)sizeof(*mem)); - - return vb; -} - -static int __videobuf_iolock(struct videobuf_queue *q, - struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf) -{ - struct videobuf_vmalloc_memory *mem = vb->priv; - int pages; - - BUG_ON(!mem); - - MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); - - switch (vb->memory) { - case V4L2_MEMORY_MMAP: - dprintk(1, "%s memory method MMAP\n", __func__); - - /* All handling should be done by __videobuf_mmap_mapper() */ - if (!mem->vaddr) { - printk(KERN_ERR "memory is not allocated/mmapped.\n"); - return -EINVAL; - } - break; - case V4L2_MEMORY_USERPTR: - pages = PAGE_ALIGN(vb->size); - - dprintk(1, "%s memory method USERPTR\n", __func__); - - if (vb->baddr) { - printk(KERN_ERR "USERPTR is currently not supported\n"); - return -EINVAL; - } - - /* The only USERPTR currently supported is the one needed for - * read() method. - */ - - mem->vaddr = vmalloc_user(pages); - if (!mem->vaddr) { - printk(KERN_ERR "vmalloc (%d pages) failed\n", pages); - return -ENOMEM; - } - dprintk(1, "vmalloc is at addr %p (%d pages)\n", - mem->vaddr, pages); - break; - case V4L2_MEMORY_OVERLAY: - default: - dprintk(1, "%s memory method OVERLAY/unknown\n", __func__); - - /* Currently, doesn't support V4L2_MEMORY_OVERLAY */ - printk(KERN_ERR "Memory method currently unsupported.\n"); - return -EINVAL; - } - - return 0; -} - -static int __videobuf_mmap_mapper(struct videobuf_queue *q, - struct videobuf_buffer *buf, - struct vm_area_struct *vma) -{ - struct videobuf_vmalloc_memory *mem; - struct videobuf_mapping *map; - int retval, pages; - - dprintk(1, "%s\n", __func__); - - /* create mapping + update buffer list */ - map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); - if (NULL == map) - return -ENOMEM; - - buf->map = map; - map->q = q; - - buf->baddr = vma->vm_start; - - mem = buf->priv; - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); - - pages = PAGE_ALIGN(vma->vm_end - vma->vm_start); - mem->vaddr = vmalloc_user(pages); - if (!mem->vaddr) { - printk(KERN_ERR "vmalloc (%d pages) failed\n", pages); - goto error; - } - dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vaddr, pages); - - /* Try to remap memory */ - retval = remap_vmalloc_range(vma, mem->vaddr, 0); - if (retval < 0) { - printk(KERN_ERR "mmap: remap failed with error %d. ", retval); - vfree(mem->vaddr); - goto error; - } - - vma->vm_ops = &videobuf_vm_ops; - vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP); - vma->vm_private_data = map; - - dprintk(1, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", - map, q, vma->vm_start, vma->vm_end, - (long int)buf->bsize, - vma->vm_pgoff, buf->i); - - videobuf_vm_open(vma); - - return 0; - -error: - mem = NULL; - kfree(map); - return -ENOMEM; -} - -static struct videobuf_qtype_ops qops = { - .magic = MAGIC_QTYPE_OPS, - - .alloc_vb = __videobuf_alloc_vb, - .iolock = __videobuf_iolock, - .mmap_mapper = __videobuf_mmap_mapper, - .vaddr = videobuf_to_vmalloc, -}; - -void videobuf_queue_vmalloc_init(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct mutex *ext_lock) -{ - videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, - priv, &qops, ext_lock); -} -EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init); - -void *videobuf_to_vmalloc(struct videobuf_buffer *buf) -{ - struct videobuf_vmalloc_memory *mem = buf->priv; - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); - - return mem->vaddr; -} -EXPORT_SYMBOL_GPL(videobuf_to_vmalloc); - -void videobuf_vmalloc_free(struct videobuf_buffer *buf) -{ - struct videobuf_vmalloc_memory *mem = buf->priv; - - /* mmapped memory can't be freed here, otherwise mmapped region - would be released, while still needed. In this case, the memory - release should happen inside videobuf_vm_close(). - So, it should free memory only if the memory were allocated for - read() operation. - */ - if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr) - return; - - if (!mem) - return; - - MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); - - vfree(mem->vaddr); - mem->vaddr = NULL; - - return; -} -EXPORT_SYMBOL_GPL(videobuf_vmalloc_free); - diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h deleted file mode 100644 index 2e01b2e9a1c0b..0000000000000 --- a/include/media/videobuf-core.h +++ /dev/null @@ -1,233 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * generic helper functions for handling video4linux capture buffers - * - * (c) 2007 Mauro Carvalho Chehab, - * - * Highly based on video-buf written originally by: - * (c) 2001,02 Gerd Knorr - * (c) 2006 Mauro Carvalho Chehab, - * (c) 2006 Ted Walther and John Sokol - */ - -#ifndef _VIDEOBUF_CORE_H -#define _VIDEOBUF_CORE_H - -#include -#include - -#define UNSET (-1U) - - -struct videobuf_buffer; -struct videobuf_queue; - -/* --------------------------------------------------------------------- */ - -/* - * A small set of helper functions to manage video4linux buffers. - * - * struct videobuf_buffer holds the data structures used by the helper - * functions, additionally some commonly used fields for v4l buffers - * (width, height, lists, waitqueue) are in there. That struct should - * be used as first element in the drivers buffer struct. - * - * about the mmap helpers (videobuf_mmap_*): - * - * The mmaper function allows to map any subset of contiguous buffers. - * This includes one mmap() call for all buffers (which the original - * video4linux API uses) as well as one mmap() for every single buffer - * (which v4l2 uses). - * - * If there is a valid mapping for a buffer, buffer->baddr/bsize holds - * userspace address + size which can be fed into the - * videobuf_dma_init_user function listed above. - * - */ - -struct videobuf_mapping { - unsigned int count; - struct videobuf_queue *q; -}; - -enum videobuf_state { - VIDEOBUF_NEEDS_INIT = 0, - VIDEOBUF_PREPARED = 1, - VIDEOBUF_QUEUED = 2, - VIDEOBUF_ACTIVE = 3, - VIDEOBUF_DONE = 4, - VIDEOBUF_ERROR = 5, - VIDEOBUF_IDLE = 6, -}; - -struct videobuf_buffer { - unsigned int i; - u32 magic; - - /* info about the buffer */ - unsigned int width; - unsigned int height; - unsigned int bytesperline; /* use only if != 0 */ - unsigned long size; - enum v4l2_field field; - enum videobuf_state state; - struct list_head stream; /* QBUF/DQBUF list */ - - /* touched by irq handler */ - struct list_head queue; - wait_queue_head_t done; - unsigned int field_count; - u64 ts; - - /* Memory type */ - enum v4l2_memory memory; - - /* buffer size */ - size_t bsize; - - /* buffer offset (mmap + overlay) */ - size_t boff; - - /* buffer addr (userland ptr!) */ - unsigned long baddr; - - /* for mmap'ed buffers */ - struct videobuf_mapping *map; - - /* Private pointer to allow specific methods to store their data */ - int privsize; - void *priv; -}; - -struct videobuf_queue_ops { - int (*buf_setup)(struct videobuf_queue *q, - unsigned int *count, unsigned int *size); - int (*buf_prepare)(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field); - void (*buf_queue)(struct videobuf_queue *q, - struct videobuf_buffer *vb); - void (*buf_release)(struct videobuf_queue *q, - struct videobuf_buffer *vb); -}; - -#define MAGIC_QTYPE_OPS 0x12261003 - -/* Helper operations - device type dependent */ -struct videobuf_qtype_ops { - u32 magic; - - struct videobuf_buffer *(*alloc_vb)(size_t size); - void *(*vaddr) (struct videobuf_buffer *buf); - int (*iolock) (struct videobuf_queue *q, - struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf); - int (*sync) (struct videobuf_queue *q, - struct videobuf_buffer *buf); - int (*mmap_mapper) (struct videobuf_queue *q, - struct videobuf_buffer *buf, - struct vm_area_struct *vma); -}; - -struct videobuf_queue { - struct mutex vb_lock; - struct mutex *ext_lock; - spinlock_t *irqlock; - struct device *dev; - - wait_queue_head_t wait; /* wait if queue is empty */ - - enum v4l2_buf_type type; - unsigned int msize; - enum v4l2_field field; - enum v4l2_field last; /* for field=V4L2_FIELD_ALTERNATE */ - struct videobuf_buffer *bufs[VIDEO_MAX_FRAME]; - const struct videobuf_queue_ops *ops; - struct videobuf_qtype_ops *int_ops; - - unsigned int streaming:1; - unsigned int reading:1; - - /* capture via mmap() + ioctl(QBUF/DQBUF) */ - struct list_head stream; - - /* capture via read() */ - unsigned int read_off; - struct videobuf_buffer *read_buf; - - /* driver private data */ - void *priv_data; -}; - -static inline void videobuf_queue_lock(struct videobuf_queue *q) -{ - if (!q->ext_lock) - mutex_lock(&q->vb_lock); -} - -static inline void videobuf_queue_unlock(struct videobuf_queue *q) -{ - if (!q->ext_lock) - mutex_unlock(&q->vb_lock); -} - -int videobuf_waiton(struct videobuf_queue *q, struct videobuf_buffer *vb, - int non_blocking, int intr); -int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf); - -struct videobuf_buffer *videobuf_alloc_vb(struct videobuf_queue *q); - -/* Used on videobuf-dvb */ -void *videobuf_queue_to_vaddr(struct videobuf_queue *q, - struct videobuf_buffer *buf); - -void videobuf_queue_core_init(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct videobuf_qtype_ops *int_ops, - struct mutex *ext_lock); -int videobuf_queue_is_busy(struct videobuf_queue *q); -void videobuf_queue_cancel(struct videobuf_queue *q); - -enum v4l2_field videobuf_next_field(struct videobuf_queue *q); -int videobuf_reqbufs(struct videobuf_queue *q, - struct v4l2_requestbuffers *req); -int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b); -int videobuf_qbuf(struct videobuf_queue *q, - struct v4l2_buffer *b); -int videobuf_dqbuf(struct videobuf_queue *q, - struct v4l2_buffer *b, int nonblocking); -int videobuf_streamon(struct videobuf_queue *q); -int videobuf_streamoff(struct videobuf_queue *q); - -void videobuf_stop(struct videobuf_queue *q); - -int videobuf_read_start(struct videobuf_queue *q); -void videobuf_read_stop(struct videobuf_queue *q); -ssize_t videobuf_read_stream(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int vbihack, int nonblocking); -ssize_t videobuf_read_one(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int nonblocking); -__poll_t videobuf_poll_stream(struct file *file, - struct videobuf_queue *q, - poll_table *wait); - -int videobuf_mmap_setup(struct videobuf_queue *q, - unsigned int bcount, unsigned int bsize, - enum v4l2_memory memory); -int __videobuf_mmap_setup(struct videobuf_queue *q, - unsigned int bcount, unsigned int bsize, - enum v4l2_memory memory); -int videobuf_mmap_free(struct videobuf_queue *q); -int videobuf_mmap_mapper(struct videobuf_queue *q, - struct vm_area_struct *vma); - -#endif diff --git a/include/media/videobuf-dma-contig.h b/include/media/videobuf-dma-contig.h deleted file mode 100644 index 525883b2c53e1..0000000000000 --- a/include/media/videobuf-dma-contig.h +++ /dev/null @@ -1,30 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * helper functions for physically contiguous capture buffers - * - * The functions support hardware lacking scatter gather support - * (i.e. the buffers must be linear in physical memory) - * - * Copyright (c) 2008 Magnus Damm - */ -#ifndef _VIDEOBUF_DMA_CONTIG_H -#define _VIDEOBUF_DMA_CONTIG_H - -#include -#include - -void videobuf_queue_dma_contig_init(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct mutex *ext_lock); - -dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf); -void videobuf_dma_contig_free(struct videobuf_queue *q, - struct videobuf_buffer *buf); - -#endif /* _VIDEOBUF_DMA_CONTIG_H */ diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h deleted file mode 100644 index 930ff8d454fc9..0000000000000 --- a/include/media/videobuf-dma-sg.h +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * helper functions for SG DMA video4linux capture buffers - * - * The functions expect the hardware being able to scatter gather - * (i.e. the buffers are not linear in physical memory, but fragmented - * into PAGE_SIZE chunks). They also assume the driver does not need - * to touch the video data. - * - * (c) 2007 Mauro Carvalho Chehab, - * - * Highly based on video-buf written originally by: - * (c) 2001,02 Gerd Knorr - * (c) 2006 Mauro Carvalho Chehab, - * (c) 2006 Ted Walther and John Sokol - */ -#ifndef _VIDEOBUF_DMA_SG_H -#define _VIDEOBUF_DMA_SG_H - -#include - -/* --------------------------------------------------------------------- */ - -/* - * A small set of helper functions to manage buffers (both userland - * and kernel) for DMA. - * - * videobuf_dma_init_*() - * creates a buffer. The userland version takes a userspace - * pointer + length. The kernel version just wants the size and - * does memory allocation too using vmalloc_32(). - * - * videobuf_dma_*() - * see Documentation/core-api/dma-api-howto.rst, these functions to - * basically the same. The map function does also build a - * scatterlist for the buffer (and unmap frees it ...) - * - * videobuf_dma_free() - * no comment ... - * - */ - -struct videobuf_dmabuf { - u32 magic; - - /* for userland buffer */ - int offset; - size_t size; - struct page **pages; - - /* for kernel buffers */ - void *vaddr; - struct page **vaddr_pages; - dma_addr_t *dma_addr; - struct device *dev; - - /* for overlay buffers (pci-pci dma) */ - dma_addr_t bus_addr; - - /* common */ - struct scatterlist *sglist; - int sglen; - unsigned long nr_pages; - int direction; -}; - -struct videobuf_dma_sg_memory { - u32 magic; - - /* for mmap'ed buffers */ - struct videobuf_dmabuf dma; -}; - -/* - * Scatter-gather DMA buffer API. - * - * These functions provide a simple way to create a page list and a - * scatter-gather list from a kernel, userspace of physical address and map the - * memory for DMA operation. - * - * Despite the name, this is totally unrelated to videobuf, except that - * videobuf-dma-sg uses the same API internally. - */ -int videobuf_dma_free(struct videobuf_dmabuf *dma); - -int videobuf_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma); -struct videobuf_dmabuf *videobuf_to_dma(struct videobuf_buffer *buf); - -void *videobuf_sg_alloc(size_t size); - -void videobuf_queue_sg_init(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct mutex *ext_lock); - -#endif /* _VIDEOBUF_DMA_SG_H */ - diff --git a/include/media/videobuf-vmalloc.h b/include/media/videobuf-vmalloc.h deleted file mode 100644 index e930dbb9d7f45..0000000000000 --- a/include/media/videobuf-vmalloc.h +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * helper functions for vmalloc capture buffers - * - * The functions expect the hardware being able to scatter gather - * (i.e. the buffers are not linear in physical memory, but fragmented - * into PAGE_SIZE chunks). They also assume the driver does not need - * to touch the video data. - * - * (c) 2007 Mauro Carvalho Chehab, - */ -#ifndef _VIDEOBUF_VMALLOC_H -#define _VIDEOBUF_VMALLOC_H - -#include - -/* --------------------------------------------------------------------- */ - -struct videobuf_vmalloc_memory { - u32 magic; - - void *vaddr; - - /* remap_vmalloc_range seems to need to run - * after mmap() on some cases */ - struct vm_area_struct *vma; -}; - -void videobuf_queue_vmalloc_init(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct mutex *ext_lock); - -void *videobuf_to_vmalloc(struct videobuf_buffer *buf); - -void videobuf_vmalloc_free(struct videobuf_buffer *buf); - -#endif -- GitLab From f329051273ca01c74a827c70d0d47f2525678b7a Mon Sep 17 00:00:00 2001 From: Marvin Lin Date: Fri, 22 Sep 2023 14:24:00 +0800 Subject: [PATCH 0314/1451] media: dt-bindings: nuvoton: Add NPCM VCD and ECE engine Add dt-bindings document for Video Capture/Differentiation Engine (VCD) and Encoding Compression Engine (ECE) present on Nuvoton NPCM SoCs. Signed-off-by: Marvin Lin Reviewed-by: Krzysztof Kozlowski Signed-off-by: Hans Verkuil --- .../bindings/media/nuvoton,npcm-ece.yaml | 43 +++++++++++ .../bindings/media/nuvoton,npcm-vcd.yaml | 72 +++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/nuvoton,npcm-ece.yaml create mode 100644 Documentation/devicetree/bindings/media/nuvoton,npcm-vcd.yaml diff --git a/Documentation/devicetree/bindings/media/nuvoton,npcm-ece.yaml b/Documentation/devicetree/bindings/media/nuvoton,npcm-ece.yaml new file mode 100644 index 0000000000000..b47468e545046 --- /dev/null +++ b/Documentation/devicetree/bindings/media/nuvoton,npcm-ece.yaml @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/nuvoton,npcm-ece.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Nuvoton NPCM Encoding Compression Engine + +maintainers: + - Joseph Liu + - Marvin Lin + +description: | + Video Encoding Compression Engine (ECE) present on Nuvoton NPCM SoCs. + +properties: + compatible: + enum: + - nuvoton,npcm750-ece + - nuvoton,npcm845-ece + + reg: + maxItems: 1 + + resets: + maxItems: 1 + +required: + - compatible + - reg + - resets + +additionalProperties: false + +examples: + - | + #include + + ece: video-codec@f0820000 { + compatible = "nuvoton,npcm750-ece"; + reg = <0xf0820000 0x2000>; + resets = <&rstc NPCM7XX_RESET_IPSRST2 NPCM7XX_RESET_ECE>; + }; diff --git a/Documentation/devicetree/bindings/media/nuvoton,npcm-vcd.yaml b/Documentation/devicetree/bindings/media/nuvoton,npcm-vcd.yaml new file mode 100644 index 0000000000000..c885f559d2e59 --- /dev/null +++ b/Documentation/devicetree/bindings/media/nuvoton,npcm-vcd.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/nuvoton,npcm-vcd.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Nuvoton NPCM Video Capture/Differentiation Engine + +maintainers: + - Joseph Liu + - Marvin Lin + +description: | + Video Capture/Differentiation Engine (VCD) present on Nuvoton NPCM SoCs. + +properties: + compatible: + enum: + - nuvoton,npcm750-vcd + - nuvoton,npcm845-vcd + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + resets: + maxItems: 1 + + nuvoton,sysgcr: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle to access GCR (Global Control Register) registers. + + nuvoton,sysgfxi: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle to access GFXI (Graphics Core Information) registers. + + nuvoton,ece: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle to access ECE (Encoding Compression Engine) registers. + + memory-region: + maxItems: 1 + description: + CMA pool to use for buffers allocation instead of the default CMA pool. + +required: + - compatible + - reg + - interrupts + - resets + - nuvoton,sysgcr + - nuvoton,sysgfxi + - nuvoton,ece + +additionalProperties: false + +examples: + - | + #include + #include + + vcd: vcd@f0810000 { + compatible = "nuvoton,npcm750-vcd"; + reg = <0xf0810000 0x10000>; + interrupts = ; + resets = <&rstc NPCM7XX_RESET_IPSRST2 NPCM7XX_RESET_VCD>; + nuvoton,sysgcr = <&gcr>; + nuvoton,sysgfxi = <&gfxi>; + nuvoton,ece = <&ece>; + }; -- GitLab From c3dea90fdfc16b768add6ef99dfd6eec8a0bf48c Mon Sep 17 00:00:00 2001 From: Marvin Lin Date: Fri, 22 Sep 2023 14:24:01 +0800 Subject: [PATCH 0315/1451] dt-bindings: soc: nuvoton: Add NPCM GFXI Add dt-bindings document for Graphics Core Information (GFXI) node. It is used by NPCM video driver to retrieve Graphics core information. Signed-off-by: Marvin Lin Reviewed-by: Krzysztof Kozlowski Signed-off-by: Hans Verkuil --- .../bindings/soc/nuvoton/nuvoton,gfxi.yaml | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/nuvoton/nuvoton,gfxi.yaml diff --git a/Documentation/devicetree/bindings/soc/nuvoton/nuvoton,gfxi.yaml b/Documentation/devicetree/bindings/soc/nuvoton/nuvoton,gfxi.yaml new file mode 100644 index 0000000000000..0222a43977ab9 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/nuvoton/nuvoton,gfxi.yaml @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/nuvoton/nuvoton,gfxi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Graphics Core Information block in Nuvoton SoCs + +maintainers: + - Joseph Liu + - Marvin Lin + +description: + The Graphics Core Information (GFXI) are a block of registers in Nuvoton SoCs + that analyzes Graphics core behavior and provides information in registers. + +properties: + compatible: + items: + - enum: + - nuvoton,npcm750-gfxi + - nuvoton,npcm845-gfxi + - const: syscon + + reg: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + gfxi: gfxi@e000 { + compatible = "nuvoton,npcm750-gfxi", "syscon"; + reg = <0xe000 0x100>; + }; -- GitLab From d62d8e7b59f9d7ed9b6eaaa788fee0d727b7d3ad Mon Sep 17 00:00:00 2001 From: Marvin Lin Date: Fri, 22 Sep 2023 14:24:02 +0800 Subject: [PATCH 0316/1451] media: v4l: Add HEXTILE compressed format Add HEXTILE compressed format which is defined in Remote Framebuffer Protocol (RFC 6143, chapter 7.7.4 Hextile Encoding) and is used by Encoding Compression Engine (ECE) present on Nuvoton NPCM SoCs. Signed-off-by: Marvin Lin Reviewed-by: Nicolas Dufresne Signed-off-by: Hans Verkuil --- Documentation/userspace-api/media/v4l/pixfmt-reserved.rst | 7 +++++++ drivers/media/v4l2-core/v4l2-ioctl.c | 1 + include/uapi/linux/videodev2.h | 1 + 3 files changed, 9 insertions(+) diff --git a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst index 296ad2025e8d3..886ba7b08d6bf 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst @@ -288,6 +288,13 @@ please make a proposal on the linux-media mailing list. - 'MT2110R' - This format is two-planar 10-Bit raster mode and having similitude with ``V4L2_PIX_FMT_MM21`` in term of alignment and tiling. Used for AVC. + * .. _V4L2-PIX-FMT-HEXTILE: + + - ``V4L2_PIX_FMT_HEXTILE`` + - 'HXTL' + - Compressed format used by Nuvoton NPCM video driver. This format is + defined in Remote Framebuffer Protocol (RFC 6143, chapter 7.7.4 Hextile + Encoding). .. raw:: latex \normalsize diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index f4d9d62790940..9b1de54ce379b 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1510,6 +1510,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_AV1_FRAME: descr = "AV1 Frame"; break; case V4L2_PIX_FMT_MT2110T: descr = "Mediatek 10bit Tile Mode"; break; case V4L2_PIX_FMT_MT2110R: descr = "Mediatek 10bit Raster Mode"; break; + case V4L2_PIX_FMT_HEXTILE: descr = "Hextile Compressed Format"; break; default: if (fmt->description[0]) return; diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 78260e5d9985f..c3d4e490ce7ca 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -804,6 +804,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_QC08C v4l2_fourcc('Q', '0', '8', 'C') /* Qualcomm 8-bit compressed */ #define V4L2_PIX_FMT_QC10C v4l2_fourcc('Q', '1', '0', 'C') /* Qualcomm 10-bit compressed */ #define V4L2_PIX_FMT_AJPG v4l2_fourcc('A', 'J', 'P', 'G') /* Aspeed JPEG */ +#define V4L2_PIX_FMT_HEXTILE v4l2_fourcc('H', 'X', 'T', 'L') /* Hextile compressed */ /* 10bit raw packed, 32 bytes for every 25 pixels, last LSB 6 bits unused */ #define V4L2_PIX_FMT_IPU3_SBGGR10 v4l2_fourcc('i', 'p', '3', 'b') /* IPU3 packed 10-bit BGGR bayer */ -- GitLab From 2817154cd18942cd89e254d3764a378518a3270f Mon Sep 17 00:00:00 2001 From: Marvin Lin Date: Fri, 22 Sep 2023 14:24:03 +0800 Subject: [PATCH 0317/1451] media: v4l2-ctrls: Add user control base for Nuvoton NPCM controls Add a control base for Nuvoton NPCM driver controls, and reserve 16 controls. Signed-off-by: Marvin Lin Signed-off-by: Hans Verkuil --- include/uapi/linux/v4l2-controls.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index c3604a0a3e30a..68db66d4aae81 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -203,6 +203,12 @@ enum v4l2_colorfx { */ #define V4L2_CID_USER_ASPEED_BASE (V4L2_CID_USER_BASE + 0x11a0) +/* + * The base for Nuvoton NPCM driver controls. + * We reserve 16 controls for this driver. + */ +#define V4L2_CID_USER_NPCM_BASE (V4L2_CID_USER_BASE + 0x11b0) + /* MPEG-class control IDs */ /* The MPEG controls are applicable to all codec controls * and the 'MPEG' part of the define is historical */ -- GitLab From 1568583b3977f232e6e7a652fd4be95a11d0ecae Mon Sep 17 00:00:00 2001 From: Marvin Lin Date: Fri, 22 Sep 2023 14:24:04 +0800 Subject: [PATCH 0318/1451] media: uapi: Add controls for NPCM video driver Create controls for Nuvoton NPCM video driver to support setting capture mode of Video Capture/Differentiation (VCD) engine and getting the count of HEXTILE rectangles that is compressed by Encoding Compression Engine (ECE). Signed-off-by: Marvin Lin Signed-off-by: Hans Verkuil --- .../userspace-api/media/drivers/index.rst | 1 + .../media/drivers/npcm-video.rst | 66 +++++++++++++++++++ include/uapi/linux/npcm-video.h | 41 ++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 Documentation/userspace-api/media/drivers/npcm-video.rst create mode 100644 include/uapi/linux/npcm-video.h diff --git a/Documentation/userspace-api/media/drivers/index.rst b/Documentation/userspace-api/media/drivers/index.rst index 6708d649afd75..783f92f01a4c8 100644 --- a/Documentation/userspace-api/media/drivers/index.rst +++ b/Documentation/userspace-api/media/drivers/index.rst @@ -37,6 +37,7 @@ For more details see the file COPYING in the source distribution of Linux. dw100 imx-uapi max2175 + npcm-video omap3isp-uapi st-vgxy61 uvcvideo diff --git a/Documentation/userspace-api/media/drivers/npcm-video.rst b/Documentation/userspace-api/media/drivers/npcm-video.rst new file mode 100644 index 0000000000000..b47771dd8b27e --- /dev/null +++ b/Documentation/userspace-api/media/drivers/npcm-video.rst @@ -0,0 +1,66 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: + +NPCM video driver +================= + +This driver is used to control the Video Capture/Differentiation (VCD) engine +and Encoding Compression Engine (ECE) present on Nuvoton NPCM SoCs. The VCD can +capture a frame from digital video input and compare two frames in memory, and +the ECE can compress the frame data into HEXTILE format. + +Driver-specific Controls +------------------------ + +V4L2_CID_NPCM_CAPTURE_MODE +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The VCD engine supports two modes: + +- COMPLETE mode: + + Capture the next complete frame into memory. + +- DIFF mode: + + Compare the incoming frame with the frame stored in memory, and updates the + differentiated frame in memory. + +Application can use ``V4L2_CID_NPCM_CAPTURE_MODE`` control to set the VCD mode +with different control values (enum v4l2_npcm_capture_mode): + +- ``V4L2_NPCM_CAPTURE_MODE_COMPLETE``: will set VCD to COMPLETE mode. +- ``V4L2_NPCM_CAPTURE_MODE_DIFF``: will set VCD to DIFF mode. + +V4L2_CID_NPCM_RECT_COUNT +~~~~~~~~~~~~~~~~~~~~~~~~ + +If using V4L2_PIX_FMT_HEXTILE format, VCD will capture frame data and then ECE +will compress the data into HEXTILE rectangles and store them in V4L2 video +buffer with the layout defined in Remote Framebuffer Protocol: +:: + + (RFC 6143, https://www.rfc-editor.org/rfc/rfc6143.html#section-7.6.1) + + +--------------+--------------+-------------------+ + | No. of bytes | Type [Value] | Description | + +--------------+--------------+-------------------+ + | 2 | U16 | x-position | + | 2 | U16 | y-position | + | 2 | U16 | width | + | 2 | U16 | height | + | 4 | S32 | encoding-type (5) | + +--------------+--------------+-------------------+ + | HEXTILE rectangle data | + +-------------------------------------------------+ + +Application can get the video buffer through VIDIOC_DQBUF, and followed by +calling ``V4L2_CID_NPCM_RECT_COUNT`` control to get the number of HEXTILE +rectangles in this buffer. + +References +---------- +include/uapi/linux/npcm-video.h + +**Copyright** |copy| 2022 Nuvoton Technologies diff --git a/include/uapi/linux/npcm-video.h b/include/uapi/linux/npcm-video.h new file mode 100644 index 0000000000000..1d39f6f38c960 --- /dev/null +++ b/include/uapi/linux/npcm-video.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * Controls header for NPCM video driver + * + * Copyright (C) 2022 Nuvoton Technologies + */ + +#ifndef _UAPI_LINUX_NPCM_VIDEO_H +#define _UAPI_LINUX_NPCM_VIDEO_H + +#include + +/* + * Check Documentation/userspace-api/media/drivers/npcm-video.rst for control + * details. + */ + +/* + * This control is meant to set the mode of NPCM Video Capture/Differentiation + * (VCD) engine. + * + * The VCD engine supports two modes: + * COMPLETE - Capture the next complete frame into memory. + * DIFF - Compare the incoming frame with the frame stored in memory, and + * updates the differentiated frame in memory. + */ +#define V4L2_CID_NPCM_CAPTURE_MODE (V4L2_CID_USER_NPCM_BASE + 0) + +enum v4l2_npcm_capture_mode { + V4L2_NPCM_CAPTURE_MODE_COMPLETE = 0, /* COMPLETE mode */ + V4L2_NPCM_CAPTURE_MODE_DIFF = 1, /* DIFF mode */ +}; + +/* + * This control is meant to get the count of compressed HEXTILE rectangles which + * is relevant to the number of differentiated frames if VCD is in DIFF mode. + * And the count will always be 1 if VCD is in COMPLETE mode. + */ +#define V4L2_CID_NPCM_RECT_COUNT (V4L2_CID_USER_NPCM_BASE + 1) + +#endif /* _UAPI_LINUX_NPCM_VIDEO_H */ -- GitLab From 46c15a4ff1f4fe078c5b250fb2570020211eab38 Mon Sep 17 00:00:00 2001 From: Marvin Lin Date: Fri, 22 Sep 2023 14:24:05 +0800 Subject: [PATCH 0319/1451] media: nuvoton: Add driver for NPCM video capture and encoding engine Add driver for Video Capture/Differentiation Engine (VCD) and Encoding Compression Engine (ECE) present on Nuvoton NPCM SoCs. As described in the datasheet NPCM750D_DS_Rev_1.0, the VCD can capture frames from digital video input and compare two frames in memory, and then the ECE can compress the frame data into HEXTILE format. This driver implements V4L2 interfaces and provides user controls to support KVM feature, also tested with VNC Viewer ver.6.22.826 and openbmc/obmc-ikvm. Signed-off-by: Marvin Lin Signed-off-by: Hans Verkuil --- MAINTAINERS | 12 + drivers/media/platform/Kconfig | 1 + drivers/media/platform/Makefile | 1 + drivers/media/platform/nuvoton/Kconfig | 15 + drivers/media/platform/nuvoton/Makefile | 2 + drivers/media/platform/nuvoton/npcm-regs.h | 152 ++ drivers/media/platform/nuvoton/npcm-video.c | 1831 +++++++++++++++++++ 7 files changed, 2014 insertions(+) create mode 100644 drivers/media/platform/nuvoton/Kconfig create mode 100644 drivers/media/platform/nuvoton/Makefile create mode 100644 drivers/media/platform/nuvoton/npcm-regs.h create mode 100644 drivers/media/platform/nuvoton/npcm-video.c diff --git a/MAINTAINERS b/MAINTAINERS index 20e37b562c9ec..03dae6ab6a888 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2480,6 +2480,18 @@ F: drivers/rtc/rtc-nct3018y.c F: include/dt-bindings/clock/nuvoton,npcm7xx-clock.h F: include/dt-bindings/clock/nuvoton,npcm845-clk.h +ARM/NUVOTON NPCM VIDEO ENGINE DRIVER +M: Joseph Liu +M: Marvin Lin +L: linux-media@vger.kernel.org +L: openbmc@lists.ozlabs.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/media/nuvoton,npcm-ece.yaml +F: Documentation/devicetree/bindings/media/nuvoton,npcm-vcd.yaml +F: Documentation/userspace-api/media/drivers/npcm-video.rst +F: drivers/media/platform/nuvoton/ +F: include/uapi/linux/npcm-video.h + ARM/NUVOTON WPCM450 ARCHITECTURE M: Jonathan Neuschäfer L: openbmc@lists.ozlabs.org (moderated for non-subscribers) diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index ee579916f8744..91e54215de3a9 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -73,6 +73,7 @@ source "drivers/media/platform/intel/Kconfig" source "drivers/media/platform/marvell/Kconfig" source "drivers/media/platform/mediatek/Kconfig" source "drivers/media/platform/microchip/Kconfig" +source "drivers/media/platform/nuvoton/Kconfig" source "drivers/media/platform/nvidia/Kconfig" source "drivers/media/platform/nxp/Kconfig" source "drivers/media/platform/qcom/Kconfig" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 5453bb868e679..3296ec1ebe16d 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -16,6 +16,7 @@ obj-y += intel/ obj-y += marvell/ obj-y += mediatek/ obj-y += microchip/ +obj-y += nuvoton/ obj-y += nvidia/ obj-y += nxp/ obj-y += qcom/ diff --git a/drivers/media/platform/nuvoton/Kconfig b/drivers/media/platform/nuvoton/Kconfig new file mode 100644 index 0000000000000..919d3166756c9 --- /dev/null +++ b/drivers/media/platform/nuvoton/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +comment "Nuvoton media platform drivers" + +config VIDEO_NPCM_VCD_ECE + tristate "Nuvoton NPCM Video Capture/Encode Engine driver" + depends on V4L_PLATFORM_DRIVERS + depends on VIDEO_DEV + select VIDEOBUF2_DMA_CONTIG + help + Support for the Video Capture/Differentiation Engine (VCD) and + Encoding Compression Engine (ECE) present on Nuvoton NPCM SoCs. + The VCD can capture a frame from digital video input and compare + two frames in memory, and then the ECE can compress the frame + data into HEXTILE format. diff --git a/drivers/media/platform/nuvoton/Makefile b/drivers/media/platform/nuvoton/Makefile new file mode 100644 index 0000000000000..74a4e3fc85557 --- /dev/null +++ b/drivers/media/platform/nuvoton/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_VIDEO_NPCM_VCD_ECE) += npcm-video.o diff --git a/drivers/media/platform/nuvoton/npcm-regs.h b/drivers/media/platform/nuvoton/npcm-regs.h new file mode 100644 index 0000000000000..4a44f47f026e8 --- /dev/null +++ b/drivers/media/platform/nuvoton/npcm-regs.h @@ -0,0 +1,152 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Register definition header for NPCM video driver + * + * Copyright (C) 2022 Nuvoton Technologies + */ + +#ifndef _NPCM_REGS_H +#define _NPCM_REGS_H + +/* VCD Registers */ +#define VCD_DIFF_TBL 0x0000 +#define VCD_FBA_ADR 0x8000 +#define VCD_FBB_ADR 0x8004 + +#define VCD_FB_LP 0x8008 +#define VCD_FBA_LP GENMASK(15, 0) +#define VCD_FBB_LP GENMASK(31, 16) + +#define VCD_CAP_RES 0x800c +#define VCD_CAP_RES_VERT_RES GENMASK(10, 0) +#define VCD_CAP_RES_HOR_RES GENMASK(26, 16) + +#define VCD_MODE 0x8014 +#define VCD_MODE_VCDE BIT(0) +#define VCD_MODE_CM565 BIT(1) +#define VCD_MODE_IDBC BIT(3) +#define VCD_MODE_KVM_BW_SET BIT(16) + +#define VCD_CMD 0x8018 +#define VCD_CMD_GO BIT(0) +#define VCD_CMD_RST BIT(1) +#define VCD_CMD_OPERATION GENMASK(6, 4) +#define VCD_CMD_OPERATION_CAPTURE 0 +#define VCD_CMD_OPERATION_COMPARE 2 + +#define VCD_STAT 0x801c +#define VCD_STAT_DONE BIT(0) +#define VCD_STAT_IFOT BIT(2) +#define VCD_STAT_IFOR BIT(3) +#define VCD_STAT_VHT_CHG BIT(5) +#define VCD_STAT_HAC_CHG BIT(8) +#define VCD_STAT_BUSY BIT(30) +#define VCD_STAT_CLEAR 0x3fff + +#define VCD_INTE 0x8020 +#define VCD_INTE_DONE_IE BIT(0) +#define VCD_INTE_IFOT_IE BIT(2) +#define VCD_INTE_IFOR_IE BIT(3) +#define VCD_INTE_VHT_IE BIT(5) +#define VCD_INTE_HAC_IE BIT(8) + +#define VCD_RCHG 0x8028 +#define VCD_RCHG_IG_CHG0 GENMASK(2, 0) +#define VCD_RCHG_TIM_PRSCL GENMASK(12, 9) + +#define VCD_VER_HI_TIM 0x8044 +#define VCD_VER_HI_TIME GENMASK(23, 0) + +#define VCD_VER_HI_LST 0x8048 +#define VCD_VER_HI_LAST GENMASK(23, 0) + +#define VCD_HOR_AC_TIM 0x804c +#define VCD_HOR_AC_TIME GENMASK(13, 0) + +#define VCD_HOR_AC_LST 0x8050 +#define VCD_HOR_AC_LAST GENMASK(13, 0) + +#define VCD_FIFO 0x805c +#define VCD_FIFO_TH 0x100350ff + +#define VCD_FB_SIZE 0x500000 /* support up to 1920 x 1200 */ +#define VCD_KVM_BW_PCLK 120000000UL +#define VCD_TIMEOUT_US 300000 + +/* ECE Registers */ +#define ECE_DDA_CTRL 0x0000 +#define ECE_DDA_CTRL_ECEEN BIT(0) +#define ECE_DDA_CTRL_INTEN BIT(8) + +#define ECE_DDA_STS 0x0004 +#define ECE_DDA_STS_CDREADY BIT(8) +#define ECE_DDA_STS_ACDRDY BIT(10) + +#define ECE_FBR_BA 0x0008 +#define ECE_ED_BA 0x000c +#define ECE_RECT_XY 0x0010 + +#define ECE_RECT_DIMEN 0x0014 +#define ECE_RECT_DIMEN_WR GENMASK(10, 0) +#define ECE_RECT_DIMEN_WLTR GENMASK(14, 11) +#define ECE_RECT_DIMEN_HR GENMASK(26, 16) +#define ECE_RECT_DIMEN_HLTR GENMASK(30, 27) + +#define ECE_RESOL 0x001c +#define ECE_RESOL_FB_LP_512 0 +#define ECE_RESOL_FB_LP_1024 1 +#define ECE_RESOL_FB_LP_2048 2 +#define ECE_RESOL_FB_LP_2560 3 +#define ECE_RESOL_FB_LP_4096 4 + +#define ECE_HEX_CTRL 0x0040 +#define ECE_HEX_CTRL_ENCDIS BIT(0) +#define ECE_HEX_CTRL_ENC_GAP GENMASK(12, 8) + +#define ECE_HEX_RECT_OFFSET 0x0048 +#define ECE_HEX_RECT_OFFSET_MASK GENMASK(22, 0) + +#define ECE_TILE_W 16 +#define ECE_TILE_H 16 +#define ECE_POLL_TIMEOUT_US 300000 + +/* GCR Registers */ +#define INTCR 0x3c +#define INTCR_GFXIFDIS GENMASK(9, 8) +#define INTCR_DEHS BIT(27) + +#define INTCR2 0x60 +#define INTCR2_GIRST2 BIT(2) +#define INTCR2_GIHCRST BIT(5) +#define INTCR2_GIVCRST BIT(6) + +/* GFXI Register */ +#define DISPST 0x00 +#define DISPST_HSCROFF BIT(1) +#define DISPST_MGAMODE BIT(7) + +#define HVCNTL 0x10 +#define HVCNTL_MASK GENMASK(7, 0) + +#define HVCNTH 0x14 +#define HVCNTH_MASK GENMASK(2, 0) + +#define VVCNTL 0x20 +#define VVCNTL_MASK GENMASK(7, 0) + +#define VVCNTH 0x24 +#define VVCNTH_MASK GENMASK(2, 0) + +#define GPLLINDIV 0x40 +#define GPLLINDIV_MASK GENMASK(5, 0) +#define GPLLINDIV_GPLLFBDV8 BIT(7) + +#define GPLLFBDIV 0x44 +#define GPLLFBDIV_MASK GENMASK(7, 0) + +#define GPLLST 0x48 +#define GPLLST_PLLOTDIV1 GENMASK(2, 0) +#define GPLLST_PLLOTDIV2 GENMASK(5, 3) +#define GPLLST_GPLLFBDV109 GENMASK(7, 6) + +#endif /* _NPCM_REGS_H */ diff --git a/drivers/media/platform/nuvoton/npcm-video.c b/drivers/media/platform/nuvoton/npcm-video.c new file mode 100644 index 0000000000000..ac8d73b794d37 --- /dev/null +++ b/drivers/media/platform/nuvoton/npcm-video.c @@ -0,0 +1,1831 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for Video Capture/Differentiation Engine (VCD) and Encoding + * Compression Engine (ECE) present on Nuvoton NPCM SoCs. + * + * Copyright (C) 2022 Nuvoton Technologies + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "npcm-regs.h" + +#define DEVICE_NAME "npcm-video" +#define MAX_WIDTH 1920 +#define MAX_HEIGHT 1200 +#define MIN_WIDTH 320 +#define MIN_HEIGHT 240 +#define MIN_LP 512 +#define MAX_LP 4096 +#define RECT_W 16 +#define RECT_H 16 +#define BITMAP_SIZE 32 + +struct npcm_video_addr { + size_t size; + dma_addr_t dma; + void *virt; +}; + +struct npcm_video_buffer { + struct vb2_v4l2_buffer vb; + struct list_head link; +}; + +#define to_npcm_video_buffer(x) \ + container_of((x), struct npcm_video_buffer, vb) + +/* + * VIDEO_STREAMING: a flag indicating if the video has started streaming + * VIDEO_CAPTURING: a flag indicating if the VCD is capturing a frame + * VIDEO_RES_CHANGING: a flag indicating if the resolution is changing + * VIDEO_STOPPED: a flag indicating if the video has stopped streaming + */ +enum { + VIDEO_STREAMING, + VIDEO_CAPTURING, + VIDEO_RES_CHANGING, + VIDEO_STOPPED, +}; + +struct rect_list { + struct v4l2_clip clip; + struct list_head list; +}; + +struct rect_list_info { + struct rect_list *list; + struct rect_list *first; + struct list_head *head; + unsigned int index; + unsigned int tile_perline; + unsigned int tile_perrow; + unsigned int offset_perline; + unsigned int tile_size; + unsigned int tile_cnt; +}; + +struct npcm_ece { + struct regmap *regmap; + atomic_t clients; + struct reset_control *reset; + bool enable; +}; + +struct npcm_video { + struct regmap *gcr_regmap; + struct regmap *gfx_regmap; + struct regmap *vcd_regmap; + + struct device *dev; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *rect_cnt_ctrl; + struct v4l2_device v4l2_dev; + struct v4l2_pix_format pix_fmt; + struct v4l2_bt_timings active_timings; + struct v4l2_bt_timings detected_timings; + unsigned int v4l2_input_status; + struct vb2_queue queue; + struct video_device vdev; + struct mutex video_lock; /* v4l2 and videobuf2 lock */ + + struct list_head buffers; + spinlock_t lock; /* buffer list lock */ + unsigned long flags; + unsigned int sequence; + + struct npcm_video_addr src; + struct reset_control *reset; + struct npcm_ece ece; + + unsigned int bytesperline; + unsigned int bytesperpixel; + unsigned int rect_cnt; + struct list_head list[VIDEO_MAX_FRAME]; + unsigned int rect[VIDEO_MAX_FRAME]; + unsigned int ctrl_cmd; + unsigned int op_cmd; +}; + +#define to_npcm_video(x) container_of((x), struct npcm_video, v4l2_dev) + +struct npcm_fmt { + unsigned int fourcc; + unsigned int bpp; /* bytes per pixel */ +}; + +static const struct npcm_fmt npcm_fmt_list[] = { + { + .fourcc = V4L2_PIX_FMT_RGB565, + .bpp = 2, + }, + { + .fourcc = V4L2_PIX_FMT_HEXTILE, + .bpp = 2, + }, +}; + +#define NUM_FORMATS ARRAY_SIZE(npcm_fmt_list) + +static const struct v4l2_dv_timings_cap npcm_video_timings_cap = { + .type = V4L2_DV_BT_656_1120, + .bt = { + .min_width = MIN_WIDTH, + .max_width = MAX_WIDTH, + .min_height = MIN_HEIGHT, + .max_height = MAX_HEIGHT, + .min_pixelclock = 6574080, /* 640 x 480 x 24Hz */ + .max_pixelclock = 138240000, /* 1920 x 1200 x 60Hz */ + .standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | + V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF, + .capabilities = V4L2_DV_BT_CAP_PROGRESSIVE | + V4L2_DV_BT_CAP_REDUCED_BLANKING | + V4L2_DV_BT_CAP_CUSTOM, + }, +}; + +static DECLARE_BITMAP(bitmap, BITMAP_SIZE); + +static const struct npcm_fmt *npcm_video_find_format(struct v4l2_format *f) +{ + const struct npcm_fmt *fmt; + unsigned int k; + + for (k = 0; k < NUM_FORMATS; k++) { + fmt = &npcm_fmt_list[k]; + if (fmt->fourcc == f->fmt.pix.pixelformat) + break; + } + + if (k == NUM_FORMATS) + return NULL; + + return &npcm_fmt_list[k]; +} + +static void npcm_video_ece_prepend_rect_header(void *addr, u16 x, u16 y, u16 w, u16 h) +{ + __be16 x_pos = cpu_to_be16(x); + __be16 y_pos = cpu_to_be16(y); + __be16 width = cpu_to_be16(w); + __be16 height = cpu_to_be16(h); + __be32 encoding = cpu_to_be32(5); /* Hextile encoding */ + + memcpy(addr, &x_pos, 2); + memcpy(addr + 2, &y_pos, 2); + memcpy(addr + 4, &width, 2); + memcpy(addr + 6, &height, 2); + memcpy(addr + 8, &encoding, 4); +} + +static unsigned int npcm_video_ece_get_ed_size(struct npcm_video *video, + unsigned int offset, void *addr) +{ + struct regmap *ece = video->ece.regmap; + unsigned int size, gap, val; + int ret; + + ret = regmap_read_poll_timeout(ece, ECE_DDA_STS, val, + (val & ECE_DDA_STS_CDREADY), 0, + ECE_POLL_TIMEOUT_US); + + if (ret) { + dev_warn(video->dev, "Wait for ECE_DDA_STS_CDREADY timeout\n"); + return 0; + } + + size = readl((void __iomem *)addr + offset); + regmap_read(ece, ECE_HEX_CTRL, &val); + gap = FIELD_GET(ECE_HEX_CTRL_ENC_GAP, val); + + dev_dbg(video->dev, "offset = %u, ed_size = %u, gap = %u\n", offset, + size, gap); + + return size + gap; +} + +static void npcm_video_ece_enc_rect(struct npcm_video *video, + unsigned int r_off_x, unsigned int r_off_y, + unsigned int r_w, unsigned int r_h) +{ + struct regmap *ece = video->ece.regmap; + unsigned int rect_offset = (r_off_y * video->bytesperline) + (r_off_x * 2); + unsigned int w_size = ECE_TILE_W, h_size = ECE_TILE_H; + unsigned int temp, w_tile, h_tile; + + regmap_update_bits(ece, ECE_DDA_CTRL, ECE_DDA_CTRL_ECEEN, 0); + regmap_update_bits(ece, ECE_DDA_CTRL, ECE_DDA_CTRL_ECEEN, ECE_DDA_CTRL_ECEEN); + regmap_write(ece, ECE_DDA_STS, ECE_DDA_STS_CDREADY | ECE_DDA_STS_ACDRDY); + regmap_write(ece, ECE_RECT_XY, rect_offset); + + w_tile = r_w / ECE_TILE_W; + h_tile = r_h / ECE_TILE_H; + + if (r_w % ECE_TILE_W) { + w_tile += 1; + w_size = r_w % ECE_TILE_W; + } + if (r_h % ECE_TILE_H || !h_tile) { + h_tile += 1; + h_size = r_h % ECE_TILE_H; + } + + temp = FIELD_PREP(ECE_RECT_DIMEN_WLTR, w_size - 1) | + FIELD_PREP(ECE_RECT_DIMEN_HLTR, h_size - 1) | + FIELD_PREP(ECE_RECT_DIMEN_WR, w_tile - 1) | + FIELD_PREP(ECE_RECT_DIMEN_HR, h_tile - 1); + + regmap_write(ece, ECE_RECT_DIMEN, temp); +} + +static unsigned int npcm_video_ece_read_rect_offset(struct npcm_video *video) +{ + struct regmap *ece = video->ece.regmap; + unsigned int offset; + + regmap_read(ece, ECE_HEX_RECT_OFFSET, &offset); + return FIELD_GET(ECE_HEX_RECT_OFFSET_MASK, offset); +} + +/* + * Set the line pitch (in bytes) for the frame buffers. + * Can be on of those values: 512, 1024, 2048, 2560 or 4096 bytes. + */ +static void npcm_video_ece_set_lp(struct npcm_video *video, unsigned int pitch) +{ + struct regmap *ece = video->ece.regmap; + unsigned int lp; + + switch (pitch) { + case 512: + lp = ECE_RESOL_FB_LP_512; + break; + case 1024: + lp = ECE_RESOL_FB_LP_1024; + break; + case 2048: + lp = ECE_RESOL_FB_LP_2048; + break; + case 2560: + lp = ECE_RESOL_FB_LP_2560; + break; + case 4096: + lp = ECE_RESOL_FB_LP_4096; + break; + default: + return; + } + + regmap_write(ece, ECE_RESOL, lp); +} + +static inline void npcm_video_ece_set_fb_addr(struct npcm_video *video, + unsigned int buffer) +{ + struct regmap *ece = video->ece.regmap; + + regmap_write(ece, ECE_FBR_BA, buffer); +} + +static inline void npcm_video_ece_set_enc_dba(struct npcm_video *video, + unsigned int addr) +{ + struct regmap *ece = video->ece.regmap; + + regmap_write(ece, ECE_ED_BA, addr); +} + +static inline void npcm_video_ece_clear_rect_offset(struct npcm_video *video) +{ + struct regmap *ece = video->ece.regmap; + + regmap_write(ece, ECE_HEX_RECT_OFFSET, 0); +} + +static void npcm_video_ece_ctrl_reset(struct npcm_video *video) +{ + struct regmap *ece = video->ece.regmap; + + regmap_update_bits(ece, ECE_DDA_CTRL, ECE_DDA_CTRL_ECEEN, 0); + regmap_update_bits(ece, ECE_HEX_CTRL, ECE_HEX_CTRL_ENCDIS, ECE_HEX_CTRL_ENCDIS); + regmap_update_bits(ece, ECE_DDA_CTRL, ECE_DDA_CTRL_ECEEN, ECE_DDA_CTRL_ECEEN); + regmap_update_bits(ece, ECE_HEX_CTRL, ECE_HEX_CTRL_ENCDIS, 0); + + npcm_video_ece_clear_rect_offset(video); +} + +static void npcm_video_ece_ip_reset(struct npcm_video *video) +{ + /* + * After resetting a module and clearing the reset bit, it should wait + * at least 10 us before accessing the module. + */ + reset_control_assert(video->ece.reset); + usleep_range(10, 20); + reset_control_deassert(video->ece.reset); + usleep_range(10, 20); +} + +static void npcm_video_ece_stop(struct npcm_video *video) +{ + struct regmap *ece = video->ece.regmap; + + regmap_update_bits(ece, ECE_DDA_CTRL, ECE_DDA_CTRL_ECEEN, 0); + regmap_update_bits(ece, ECE_DDA_CTRL, ECE_DDA_CTRL_INTEN, 0); + regmap_update_bits(ece, ECE_HEX_CTRL, ECE_HEX_CTRL_ENCDIS, ECE_HEX_CTRL_ENCDIS); + npcm_video_ece_clear_rect_offset(video); +} + +static bool npcm_video_alloc_fb(struct npcm_video *video, + struct npcm_video_addr *addr) +{ + addr->virt = dma_alloc_coherent(video->dev, VCD_FB_SIZE, &addr->dma, + GFP_KERNEL); + if (!addr->virt) + return false; + + addr->size = VCD_FB_SIZE; + return true; +} + +static void npcm_video_free_fb(struct npcm_video *video, + struct npcm_video_addr *addr) +{ + dma_free_coherent(video->dev, addr->size, addr->virt, addr->dma); + addr->size = 0; + addr->dma = 0ULL; + addr->virt = NULL; +} + +static void npcm_video_free_diff_table(struct npcm_video *video) +{ + struct list_head *head, *pos, *nx; + struct rect_list *tmp; + unsigned int i; + + for (i = 0; i < video->queue.num_buffers; i++) { + head = &video->list[i]; + list_for_each_safe(pos, nx, head) { + tmp = list_entry(pos, struct rect_list, list); + list_del(&tmp->list); + kfree(tmp); + } + } +} + +static unsigned int npcm_video_add_rect(struct npcm_video *video, + unsigned int index, + unsigned int x, unsigned int y, + unsigned int w, unsigned int h) +{ + struct list_head *head = &video->list[index]; + struct rect_list *list = NULL; + struct v4l2_rect *r; + + list = kzalloc(sizeof(*list), GFP_KERNEL); + if (!list) + return 0; + + r = &list->clip.c; + r->left = x; + r->top = y; + r->width = w; + r->height = h; + + list_add_tail(&list->list, head); + return 1; +} + +static void npcm_video_merge_rect(struct npcm_video *video, + struct rect_list_info *info) +{ + struct list_head *head = info->head; + struct rect_list *list = info->list, *first = info->first; + struct v4l2_rect *r = &list->clip.c, *f = &first->clip.c; + + if (!first) { + first = list; + info->first = first; + list_add_tail(&list->list, head); + video->rect_cnt++; + } else { + if ((r->left == (f->left + f->width)) && r->top == f->top) { + f->width += r->width; + kfree(list); + } else if ((r->top == (f->top + f->height)) && + (r->left == f->left)) { + f->height += r->height; + kfree(list); + } else if (((r->top > f->top) && + (r->top < (f->top + f->height))) && + ((r->left > f->left) && + (r->left < (f->left + f->width)))) { + kfree(list); + } else { + list_add_tail(&list->list, head); + video->rect_cnt++; + info->first = list; + } + } +} + +static struct rect_list *npcm_video_new_rect(struct npcm_video *video, + unsigned int offset, + unsigned int index) +{ + struct v4l2_bt_timings *act = &video->active_timings; + struct rect_list *list = NULL; + struct v4l2_rect *r; + + list = kzalloc(sizeof(*list), GFP_KERNEL); + if (!list) + return NULL; + + r = &list->clip.c; + + r->left = (offset << 4); + r->top = (index >> 2); + r->width = RECT_W; + r->height = RECT_H; + if ((r->left + RECT_W) > act->width) + r->width = act->width - r->left; + if ((r->top + RECT_H) > act->height) + r->height = act->height - r->top; + + return list; +} + +static int npcm_video_find_rect(struct npcm_video *video, + struct rect_list_info *info, + unsigned int offset) +{ + if (offset < info->tile_perline) { + info->list = npcm_video_new_rect(video, offset, info->index); + if (!info->list) { + dev_err(video->dev, "Failed to allocate rect_list\n"); + return -ENOMEM; + } + + npcm_video_merge_rect(video, info); + } + return 0; +} + +static int npcm_video_build_table(struct npcm_video *video, + struct rect_list_info *info) +{ + struct regmap *vcd = video->vcd_regmap; + unsigned int j, bit, value; + int ret; + + for (j = 0; j < info->offset_perline; j += 4) { + regmap_read(vcd, VCD_DIFF_TBL + (j + info->index), &value); + + bitmap_from_arr32(bitmap, &value, BITMAP_SIZE); + + for_each_set_bit(bit, bitmap, BITMAP_SIZE) { + ret = npcm_video_find_rect(video, info, bit + (j << 3)); + if (ret) + return ret; + } + } + info->index += 64; + return info->tile_perline; +} + +static void npcm_video_get_rect_list(struct npcm_video *video, unsigned int index) +{ + struct v4l2_bt_timings *act = &video->active_timings; + struct rect_list_info info; + unsigned int tile_cnt = 0, mod; + int ret = 0; + + memset(&info, 0, sizeof(struct rect_list_info)); + info.head = &video->list[index]; + + info.tile_perline = act->width >> 4; + mod = act->width % RECT_W; + if (mod != 0) + info.tile_perline += 1; + + info.tile_perrow = act->height >> 4; + mod = act->height % RECT_H; + if (mod != 0) + info.tile_perrow += 1; + + info.tile_size = info.tile_perrow * info.tile_perline; + + info.offset_perline = info.tile_perline >> 5; + mod = info.tile_perline % 32; + if (mod != 0) + info.offset_perline += 1; + + info.offset_perline *= 4; + + do { + ret = npcm_video_build_table(video, &info); + if (ret < 0) + return; + + tile_cnt += ret; + } while (tile_cnt < info.tile_size); +} + +static unsigned int npcm_video_is_mga(struct npcm_video *video) +{ + struct regmap *gfxi = video->gfx_regmap; + unsigned int dispst; + + regmap_read(gfxi, DISPST, &dispst); + return ((dispst & DISPST_MGAMODE) == DISPST_MGAMODE); +} + +static unsigned int npcm_video_hres(struct npcm_video *video) +{ + struct regmap *gfxi = video->gfx_regmap; + unsigned int hvcnth, hvcntl, apb_hor_res; + + regmap_read(gfxi, HVCNTH, &hvcnth); + regmap_read(gfxi, HVCNTL, &hvcntl); + apb_hor_res = (((hvcnth & HVCNTH_MASK) << 8) + (hvcntl & HVCNTL_MASK) + 1); + + return apb_hor_res; +} + +static unsigned int npcm_video_vres(struct npcm_video *video) +{ + struct regmap *gfxi = video->gfx_regmap; + unsigned int vvcnth, vvcntl, apb_ver_res; + + regmap_read(gfxi, VVCNTH, &vvcnth); + regmap_read(gfxi, VVCNTL, &vvcntl); + + apb_ver_res = (((vvcnth & VVCNTH_MASK) << 8) + (vvcntl & VVCNTL_MASK)); + + return apb_ver_res; +} + +static int npcm_video_capres(struct npcm_video *video, unsigned int hor_res, + unsigned int vert_res) +{ + struct regmap *vcd = video->vcd_regmap; + unsigned int res, cap_res; + + if (hor_res > MAX_WIDTH || vert_res > MAX_HEIGHT) + return -EINVAL; + + res = FIELD_PREP(VCD_CAP_RES_VERT_RES, vert_res) | + FIELD_PREP(VCD_CAP_RES_HOR_RES, hor_res); + + regmap_write(vcd, VCD_CAP_RES, res); + regmap_read(vcd, VCD_CAP_RES, &cap_res); + + if (cap_res != res) + return -EINVAL; + + return 0; +} + +static void npcm_video_vcd_ip_reset(struct npcm_video *video) +{ + /* + * After resetting a module and clearing the reset bit, it should wait + * at least 10 us before accessing the module. + */ + reset_control_assert(video->reset); + usleep_range(10, 20); + reset_control_deassert(video->reset); + usleep_range(10, 20); +} + +static void npcm_video_vcd_state_machine_reset(struct npcm_video *video) +{ + struct regmap *vcd = video->vcd_regmap; + + regmap_update_bits(vcd, VCD_MODE, VCD_MODE_VCDE, 0); + regmap_update_bits(vcd, VCD_MODE, VCD_MODE_IDBC, 0); + regmap_update_bits(vcd, VCD_CMD, VCD_CMD_RST, VCD_CMD_RST); + + /* + * VCD_CMD_RST will reset VCD internal state machines and clear FIFOs, + * it should wait at least 800 us for the reset operations completed. + */ + usleep_range(800, 1000); + + regmap_write(vcd, VCD_STAT, VCD_STAT_CLEAR); + regmap_update_bits(vcd, VCD_MODE, VCD_MODE_VCDE, VCD_MODE_VCDE); + regmap_update_bits(vcd, VCD_MODE, VCD_MODE_IDBC, VCD_MODE_IDBC); +} + +static void npcm_video_gfx_reset(struct npcm_video *video) +{ + struct regmap *gcr = video->gcr_regmap; + + regmap_update_bits(gcr, INTCR2, INTCR2_GIRST2, INTCR2_GIRST2); + npcm_video_vcd_state_machine_reset(video); + regmap_update_bits(gcr, INTCR2, INTCR2_GIRST2, 0); +} + +static void npcm_video_kvm_bw(struct npcm_video *video, bool set_bw) +{ + struct regmap *vcd = video->vcd_regmap; + + if (set_bw || !npcm_video_is_mga(video)) + regmap_update_bits(vcd, VCD_MODE, VCD_MODE_KVM_BW_SET, + VCD_MODE_KVM_BW_SET); + else + regmap_update_bits(vcd, VCD_MODE, VCD_MODE_KVM_BW_SET, 0); +} + +static unsigned int npcm_video_pclk(struct npcm_video *video) +{ + struct regmap *gfxi = video->gfx_regmap; + unsigned int tmp, pllfbdiv, pllinotdiv, gpllfbdiv; + unsigned int gpllfbdv109, gpllfbdv8, gpllindiv; + unsigned int gpllst_pllotdiv1, gpllst_pllotdiv2; + + regmap_read(gfxi, GPLLST, &tmp); + gpllfbdv109 = FIELD_GET(GPLLST_GPLLFBDV109, tmp); + gpllst_pllotdiv1 = FIELD_GET(GPLLST_PLLOTDIV1, tmp); + gpllst_pllotdiv2 = FIELD_GET(GPLLST_PLLOTDIV2, tmp); + + regmap_read(gfxi, GPLLINDIV, &tmp); + gpllfbdv8 = FIELD_GET(GPLLINDIV_GPLLFBDV8, tmp); + gpllindiv = FIELD_GET(GPLLINDIV_MASK, tmp); + + regmap_read(gfxi, GPLLFBDIV, &tmp); + gpllfbdiv = FIELD_GET(GPLLFBDIV_MASK, tmp); + + pllfbdiv = (512 * gpllfbdv109 + 256 * gpllfbdv8 + gpllfbdiv); + pllinotdiv = (gpllindiv * gpllst_pllotdiv1 * gpllst_pllotdiv2); + if (pllfbdiv == 0 || pllinotdiv == 0) + return 0; + + return ((pllfbdiv * 25000) / pllinotdiv) * 1000; +} + +static unsigned int npcm_video_get_bpp(struct npcm_video *video) +{ + const struct npcm_fmt *fmt; + unsigned int k; + + for (k = 0; k < NUM_FORMATS; k++) { + fmt = &npcm_fmt_list[k]; + if (fmt->fourcc == video->pix_fmt.pixelformat) + break; + } + + return fmt->bpp; +} + +/* + * Pitch must be a power of 2, >= linebytes, + * at least 512, and no more than 4096. + */ +static void npcm_video_set_linepitch(struct npcm_video *video, + unsigned int linebytes) +{ + struct regmap *vcd = video->vcd_regmap; + unsigned int pitch = MIN_LP; + + while ((pitch < linebytes) && (pitch < MAX_LP)) + pitch *= 2; + + regmap_write(vcd, VCD_FB_LP, FIELD_PREP(VCD_FBA_LP, pitch) | + FIELD_PREP(VCD_FBB_LP, pitch)); +} + +static unsigned int npcm_video_get_linepitch(struct npcm_video *video) +{ + struct regmap *vcd = video->vcd_regmap; + unsigned int linepitch; + + regmap_read(vcd, VCD_FB_LP, &linepitch); + return FIELD_GET(VCD_FBA_LP, linepitch); +} + +static void npcm_video_command(struct npcm_video *video, unsigned int value) +{ + struct regmap *vcd = video->vcd_regmap; + unsigned int cmd; + + regmap_write(vcd, VCD_STAT, VCD_STAT_CLEAR); + regmap_read(vcd, VCD_CMD, &cmd); + cmd |= FIELD_PREP(VCD_CMD_OPERATION, value); + + regmap_write(vcd, VCD_CMD, cmd); + regmap_update_bits(vcd, VCD_CMD, VCD_CMD_GO, VCD_CMD_GO); + video->op_cmd = value; +} + +static void npcm_video_init_reg(struct npcm_video *video) +{ + struct regmap *gcr = video->gcr_regmap, *vcd = video->vcd_regmap; + + /* Selects Data Enable */ + regmap_update_bits(gcr, INTCR, INTCR_DEHS, 0); + + /* Enable display of KVM GFX and access to memory */ + regmap_update_bits(gcr, INTCR, INTCR_GFXIFDIS, 0); + + /* Active Vertical/Horizontal Counters Reset */ + regmap_update_bits(gcr, INTCR2, INTCR2_GIHCRST | INTCR2_GIVCRST, + INTCR2_GIHCRST | INTCR2_GIVCRST); + + /* Reset video modules */ + npcm_video_vcd_ip_reset(video); + npcm_video_gfx_reset(video); + + /* Set the FIFO thresholds */ + regmap_write(vcd, VCD_FIFO, VCD_FIFO_TH); + + /* Set RCHG timer */ + regmap_write(vcd, VCD_RCHG, FIELD_PREP(VCD_RCHG_TIM_PRSCL, 0xf) | + FIELD_PREP(VCD_RCHG_IG_CHG0, 0x3)); + + /* Set video mode */ + regmap_write(vcd, VCD_MODE, VCD_MODE_VCDE | VCD_MODE_CM565 | + VCD_MODE_IDBC | VCD_MODE_KVM_BW_SET); +} + +static int npcm_video_start_frame(struct npcm_video *video) +{ + struct npcm_video_buffer *buf; + struct regmap *vcd = video->vcd_regmap; + unsigned long flags; + unsigned int val; + int ret; + + if (video->v4l2_input_status) { + dev_dbg(video->dev, "No video signal; skip capture frame\n"); + return 0; + } + + ret = regmap_read_poll_timeout(vcd, VCD_STAT, val, !(val & VCD_STAT_BUSY), + 1000, VCD_TIMEOUT_US); + if (ret) { + dev_err(video->dev, "Wait for VCD_STAT_BUSY timeout\n"); + return -EBUSY; + } + + spin_lock_irqsave(&video->lock, flags); + buf = list_first_entry_or_null(&video->buffers, + struct npcm_video_buffer, link); + if (!buf) { + spin_unlock_irqrestore(&video->lock, flags); + dev_dbg(video->dev, "No empty buffers; skip capture frame\n"); + return 0; + } + + set_bit(VIDEO_CAPTURING, &video->flags); + spin_unlock_irqrestore(&video->lock, flags); + + npcm_video_vcd_state_machine_reset(video); + + regmap_read(vcd, VCD_HOR_AC_TIM, &val); + regmap_update_bits(vcd, VCD_HOR_AC_LST, VCD_HOR_AC_LAST, + FIELD_GET(VCD_HOR_AC_TIME, val)); + + regmap_read(vcd, VCD_VER_HI_TIM, &val); + regmap_update_bits(vcd, VCD_VER_HI_LST, VCD_VER_HI_LAST, + FIELD_GET(VCD_VER_HI_TIME, val)); + + regmap_update_bits(vcd, VCD_INTE, VCD_INTE_DONE_IE | VCD_INTE_IFOT_IE | + VCD_INTE_IFOR_IE | VCD_INTE_HAC_IE | VCD_INTE_VHT_IE, + VCD_INTE_DONE_IE | VCD_INTE_IFOT_IE | VCD_INTE_IFOR_IE | + VCD_INTE_HAC_IE | VCD_INTE_VHT_IE); + + npcm_video_command(video, video->ctrl_cmd); + + return 0; +} + +static void npcm_video_bufs_done(struct npcm_video *video, + enum vb2_buffer_state state) +{ + struct npcm_video_buffer *buf; + unsigned long flags; + + spin_lock_irqsave(&video->lock, flags); + list_for_each_entry(buf, &video->buffers, link) + vb2_buffer_done(&buf->vb.vb2_buf, state); + + INIT_LIST_HEAD(&video->buffers); + spin_unlock_irqrestore(&video->lock, flags); +} + +static void npcm_video_get_diff_rect(struct npcm_video *video, unsigned int index) +{ + unsigned int width = video->active_timings.width; + unsigned int height = video->active_timings.height; + + if (video->op_cmd != VCD_CMD_OPERATION_CAPTURE) { + video->rect_cnt = 0; + npcm_video_get_rect_list(video, index); + video->rect[index] = video->rect_cnt; + } else { + video->rect[index] = npcm_video_add_rect(video, index, 0, 0, + width, height); + } +} + +static void npcm_video_detect_resolution(struct npcm_video *video) +{ + struct v4l2_bt_timings *act = &video->active_timings; + struct v4l2_bt_timings *det = &video->detected_timings; + struct regmap *gfxi = video->gfx_regmap; + unsigned int dispst; + + video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; + det->width = npcm_video_hres(video); + det->height = npcm_video_vres(video); + + if (act->width != det->width || act->height != det->height) { + dev_dbg(video->dev, "Resolution changed\n"); + + if (npcm_video_hres(video) > 0 && npcm_video_vres(video) > 0) { + if (test_bit(VIDEO_STREAMING, &video->flags)) { + /* + * Wait for resolution is available, + * and it is also captured by host. + */ + do { + mdelay(100); + regmap_read(gfxi, DISPST, &dispst); + } while (npcm_video_vres(video) < 100 || + npcm_video_pclk(video) == 0 || + (dispst & DISPST_HSCROFF)); + } + + det->width = npcm_video_hres(video); + det->height = npcm_video_vres(video); + det->pixelclock = npcm_video_pclk(video); + } + + clear_bit(VIDEO_RES_CHANGING, &video->flags); + } + + if (det->width && det->height) + video->v4l2_input_status = 0; + + dev_dbg(video->dev, "Got resolution[%dx%d] -> [%dx%d], status %d\n", + act->width, act->height, det->width, det->height, + video->v4l2_input_status); +} + +static int npcm_video_set_resolution(struct npcm_video *video, + struct v4l2_bt_timings *timing) +{ + struct regmap *vcd = video->vcd_regmap; + unsigned int mode; + + if (npcm_video_capres(video, timing->width, timing->height)) { + dev_err(video->dev, "Failed to set VCD_CAP_RES\n"); + return -EINVAL; + } + + video->active_timings = *timing; + video->bytesperpixel = npcm_video_get_bpp(video); + npcm_video_set_linepitch(video, timing->width * video->bytesperpixel); + video->bytesperline = npcm_video_get_linepitch(video); + video->pix_fmt.width = timing->width ? timing->width : MIN_WIDTH; + video->pix_fmt.height = timing->height ? timing->height : MIN_HEIGHT; + video->pix_fmt.sizeimage = video->pix_fmt.width * video->pix_fmt.height * + video->bytesperpixel; + video->pix_fmt.bytesperline = video->bytesperline; + + npcm_video_kvm_bw(video, timing->pixelclock > VCD_KVM_BW_PCLK); + npcm_video_gfx_reset(video); + regmap_read(vcd, VCD_MODE, &mode); + + dev_dbg(video->dev, "VCD mode = 0x%x, %s mode\n", mode, + npcm_video_is_mga(video) ? "Hi Res" : "VGA"); + + dev_dbg(video->dev, + "Digital mode: %d x %d x %d, pixelclock %lld, bytesperline %d\n", + timing->width, timing->height, video->bytesperpixel, + timing->pixelclock, video->bytesperline); + + return 0; +} + +static void npcm_video_start(struct npcm_video *video) +{ + npcm_video_init_reg(video); + + if (!npcm_video_alloc_fb(video, &video->src)) { + dev_err(video->dev, "Failed to allocate VCD frame buffer\n"); + return; + } + + npcm_video_detect_resolution(video); + if (npcm_video_set_resolution(video, &video->detected_timings)) { + dev_err(video->dev, "Failed to set resolution\n"); + return; + } + + /* Set frame buffer physical address */ + regmap_write(video->vcd_regmap, VCD_FBA_ADR, video->src.dma); + regmap_write(video->vcd_regmap, VCD_FBB_ADR, video->src.dma); + + if (video->ece.enable && atomic_inc_return(&video->ece.clients) == 1) { + npcm_video_ece_ip_reset(video); + npcm_video_ece_ctrl_reset(video); + npcm_video_ece_set_fb_addr(video, video->src.dma); + npcm_video_ece_set_lp(video, video->bytesperline); + + dev_dbg(video->dev, "ECE open: client %d\n", + atomic_read(&video->ece.clients)); + } +} + +static void npcm_video_stop(struct npcm_video *video) +{ + struct regmap *vcd = video->vcd_regmap; + + set_bit(VIDEO_STOPPED, &video->flags); + + regmap_write(vcd, VCD_INTE, 0); + regmap_write(vcd, VCD_MODE, 0); + regmap_write(vcd, VCD_RCHG, 0); + regmap_write(vcd, VCD_STAT, VCD_STAT_CLEAR); + + if (video->src.size) + npcm_video_free_fb(video, &video->src); + + npcm_video_free_diff_table(video); + video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; + video->flags = 0; + video->ctrl_cmd = VCD_CMD_OPERATION_CAPTURE; + + if (video->ece.enable && atomic_dec_return(&video->ece.clients) == 0) { + npcm_video_ece_stop(video); + dev_dbg(video->dev, "ECE close: client %d\n", + atomic_read(&video->ece.clients)); + } +} + +static unsigned int npcm_video_raw(struct npcm_video *video, int index, void *addr) +{ + unsigned int width = video->active_timings.width; + unsigned int height = video->active_timings.height; + unsigned int i, len, offset, bytes = 0; + + video->rect[index] = npcm_video_add_rect(video, index, 0, 0, width, height); + + for (i = 0; i < height; i++) { + len = width * video->bytesperpixel; + offset = i * video->bytesperline; + + memcpy(addr + bytes, video->src.virt + offset, len); + bytes += len; + } + + return bytes; +} + +static unsigned int npcm_video_hextile(struct npcm_video *video, unsigned int index, + unsigned int dma_addr, void *vaddr) +{ + struct rect_list *rect_list; + struct v4l2_rect *rect; + unsigned int offset, len, bytes = 0; + + npcm_video_ece_ctrl_reset(video); + npcm_video_ece_clear_rect_offset(video); + npcm_video_ece_set_fb_addr(video, video->src.dma); + + /* Set base address of encoded data to video buffer */ + npcm_video_ece_set_enc_dba(video, dma_addr); + + npcm_video_ece_set_lp(video, video->bytesperline); + npcm_video_get_diff_rect(video, index); + + list_for_each_entry(rect_list, &video->list[index], list) { + rect = &rect_list->clip.c; + offset = npcm_video_ece_read_rect_offset(video); + npcm_video_ece_enc_rect(video, rect->left, rect->top, + rect->width, rect->height); + + len = npcm_video_ece_get_ed_size(video, offset, vaddr); + npcm_video_ece_prepend_rect_header(vaddr + offset, + rect->left, rect->top, + rect->width, rect->height); + bytes += len; + } + + return bytes; +} + +static irqreturn_t npcm_video_irq(int irq, void *arg) +{ + struct npcm_video *video = arg; + struct regmap *vcd = video->vcd_regmap; + struct npcm_video_buffer *buf; + unsigned int index, size, status, fmt; + dma_addr_t dma_addr; + void *addr; + static const struct v4l2_event ev = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + + regmap_read(vcd, VCD_STAT, &status); + dev_dbg(video->dev, "VCD irq status 0x%x\n", status); + + regmap_write(vcd, VCD_STAT, VCD_STAT_CLEAR); + + if (test_bit(VIDEO_STOPPED, &video->flags) || + !test_bit(VIDEO_STREAMING, &video->flags)) + return IRQ_NONE; + + if (status & VCD_STAT_DONE) { + regmap_write(vcd, VCD_INTE, 0); + spin_lock(&video->lock); + clear_bit(VIDEO_CAPTURING, &video->flags); + buf = list_first_entry_or_null(&video->buffers, + struct npcm_video_buffer, link); + if (!buf) { + spin_unlock(&video->lock); + return IRQ_NONE; + } + + addr = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); + index = buf->vb.vb2_buf.index; + fmt = video->pix_fmt.pixelformat; + + switch (fmt) { + case V4L2_PIX_FMT_RGB565: + size = npcm_video_raw(video, index, addr); + break; + case V4L2_PIX_FMT_HEXTILE: + dma_addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); + size = npcm_video_hextile(video, index, dma_addr, addr); + break; + default: + spin_unlock(&video->lock); + return IRQ_NONE; + } + + vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size); + buf->vb.vb2_buf.timestamp = ktime_get_ns(); + buf->vb.sequence = video->sequence++; + buf->vb.field = V4L2_FIELD_NONE; + + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + list_del(&buf->link); + spin_unlock(&video->lock); + + if (npcm_video_start_frame(video)) + dev_err(video->dev, "Failed to capture next frame\n"); + } + + /* Resolution changed */ + if (status & VCD_STAT_VHT_CHG || status & VCD_STAT_HAC_CHG) { + if (!test_bit(VIDEO_RES_CHANGING, &video->flags)) { + set_bit(VIDEO_RES_CHANGING, &video->flags); + + vb2_queue_error(&video->queue); + v4l2_event_queue(&video->vdev, &ev); + } + } + + if (status & VCD_STAT_IFOR || status & VCD_STAT_IFOT) { + dev_warn(video->dev, "VCD FIFO overrun or over thresholds\n"); + if (npcm_video_start_frame(video)) + dev_err(video->dev, "Failed to recover from FIFO overrun\n"); + } + + return IRQ_HANDLED; +} + +static int npcm_video_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, DEVICE_NAME, sizeof(cap->driver)); + strscpy(cap->card, "NPCM Video Engine", sizeof(cap->card)); + + return 0; +} + +static int npcm_video_enum_format(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + struct npcm_video *video = video_drvdata(file); + const struct npcm_fmt *fmt; + + if (f->index >= NUM_FORMATS) + return -EINVAL; + + fmt = &npcm_fmt_list[f->index]; + if (fmt->fourcc == V4L2_PIX_FMT_HEXTILE && !video->ece.enable) + return -EINVAL; + + f->pixelformat = fmt->fourcc; + return 0; +} + +static int npcm_video_try_format(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct npcm_video *video = video_drvdata(file); + const struct npcm_fmt *fmt; + + fmt = npcm_video_find_format(f); + + /* If format not found or HEXTILE not supported, use RGB565 as default */ + if (!fmt || (fmt->fourcc == V4L2_PIX_FMT_HEXTILE && !video->ece.enable)) + f->fmt.pix.pixelformat = npcm_fmt_list[0].fourcc; + + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; + f->fmt.pix.quantization = V4L2_QUANTIZATION_FULL_RANGE; + f->fmt.pix.width = video->pix_fmt.width; + f->fmt.pix.height = video->pix_fmt.height; + f->fmt.pix.bytesperline = video->bytesperline; + f->fmt.pix.sizeimage = video->pix_fmt.sizeimage; + + return 0; +} + +static int npcm_video_get_format(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct npcm_video *video = video_drvdata(file); + + f->fmt.pix = video->pix_fmt; + return 0; +} + +static int npcm_video_set_format(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct npcm_video *video = video_drvdata(file); + int ret; + + ret = npcm_video_try_format(file, fh, f); + if (ret) + return ret; + + if (vb2_is_busy(&video->queue)) { + dev_err(video->dev, "%s device busy\n", __func__); + return -EBUSY; + } + + video->pix_fmt.pixelformat = f->fmt.pix.pixelformat; + return 0; +} + +static int npcm_video_enum_input(struct file *file, void *fh, + struct v4l2_input *inp) +{ + struct npcm_video *video = video_drvdata(file); + + if (inp->index) + return -EINVAL; + + strscpy(inp->name, "Host VGA capture", sizeof(inp->name)); + inp->type = V4L2_INPUT_TYPE_CAMERA; + inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; + inp->status = video->v4l2_input_status; + + return 0; +} + +static int npcm_video_get_input(struct file *file, void *fh, unsigned int *i) +{ + *i = 0; + + return 0; +} + +static int npcm_video_set_input(struct file *file, void *fh, unsigned int i) +{ + if (i) + return -EINVAL; + + return 0; +} + +static int npcm_video_set_dv_timings(struct file *file, void *fh, + struct v4l2_dv_timings *timings) +{ + struct npcm_video *video = video_drvdata(file); + int rc; + + if (timings->bt.width == video->active_timings.width && + timings->bt.height == video->active_timings.height) + return 0; + + if (vb2_is_busy(&video->queue)) { + dev_err(video->dev, "%s device busy\n", __func__); + return -EBUSY; + } + + rc = npcm_video_set_resolution(video, &timings->bt); + if (rc) + return rc; + + timings->type = V4L2_DV_BT_656_1120; + + return 0; +} + +static int npcm_video_get_dv_timings(struct file *file, void *fh, + struct v4l2_dv_timings *timings) +{ + struct npcm_video *video = video_drvdata(file); + + timings->type = V4L2_DV_BT_656_1120; + timings->bt = video->active_timings; + + return 0; +} + +static int npcm_video_query_dv_timings(struct file *file, void *fh, + struct v4l2_dv_timings *timings) +{ + struct npcm_video *video = video_drvdata(file); + + npcm_video_detect_resolution(video); + timings->type = V4L2_DV_BT_656_1120; + timings->bt = video->detected_timings; + + return video->v4l2_input_status ? -ENOLINK : 0; +} + +static int npcm_video_enum_dv_timings(struct file *file, void *fh, + struct v4l2_enum_dv_timings *timings) +{ + return v4l2_enum_dv_timings_cap(timings, &npcm_video_timings_cap, + NULL, NULL); +} + +static int npcm_video_dv_timings_cap(struct file *file, void *fh, + struct v4l2_dv_timings_cap *cap) +{ + *cap = npcm_video_timings_cap; + + return 0; +} + +static int npcm_video_sub_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subscribe(fh, sub); + } + + return v4l2_ctrl_subscribe_event(fh, sub); +} + +static const struct v4l2_ioctl_ops npcm_video_ioctls = { + .vidioc_querycap = npcm_video_querycap, + + .vidioc_enum_fmt_vid_cap = npcm_video_enum_format, + .vidioc_g_fmt_vid_cap = npcm_video_get_format, + .vidioc_s_fmt_vid_cap = npcm_video_set_format, + .vidioc_try_fmt_vid_cap = npcm_video_try_format, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + + .vidioc_enum_input = npcm_video_enum_input, + .vidioc_g_input = npcm_video_get_input, + .vidioc_s_input = npcm_video_set_input, + + .vidioc_s_dv_timings = npcm_video_set_dv_timings, + .vidioc_g_dv_timings = npcm_video_get_dv_timings, + .vidioc_query_dv_timings = npcm_video_query_dv_timings, + .vidioc_enum_dv_timings = npcm_video_enum_dv_timings, + .vidioc_dv_timings_cap = npcm_video_dv_timings_cap, + + .vidioc_subscribe_event = npcm_video_sub_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int npcm_video_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct npcm_video *video = container_of(ctrl->handler, struct npcm_video, + ctrl_handler); + + switch (ctrl->id) { + case V4L2_CID_NPCM_CAPTURE_MODE: + if (ctrl->val == V4L2_NPCM_CAPTURE_MODE_COMPLETE) + video->ctrl_cmd = VCD_CMD_OPERATION_CAPTURE; + else if (ctrl->val == V4L2_NPCM_CAPTURE_MODE_DIFF) + video->ctrl_cmd = VCD_CMD_OPERATION_COMPARE; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops npcm_video_ctrl_ops = { + .s_ctrl = npcm_video_set_ctrl, +}; + +static const char * const npcm_ctrl_capture_mode_menu[] = { + "COMPLETE", + "DIFF", + NULL, +}; + +static const struct v4l2_ctrl_config npcm_ctrl_capture_mode = { + .ops = &npcm_video_ctrl_ops, + .id = V4L2_CID_NPCM_CAPTURE_MODE, + .name = "NPCM Video Capture Mode", + .type = V4L2_CTRL_TYPE_MENU, + .min = 0, + .max = V4L2_NPCM_CAPTURE_MODE_DIFF, + .def = 0, + .qmenu = npcm_ctrl_capture_mode_menu, +}; + +/* + * This control value is set when a buffer is dequeued by userspace, i.e. in + * npcm_video_buf_finish function. + */ +static const struct v4l2_ctrl_config npcm_ctrl_rect_count = { + .id = V4L2_CID_NPCM_RECT_COUNT, + .name = "NPCM Hextile Rectangle Count", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (MAX_WIDTH / RECT_W) * (MAX_HEIGHT / RECT_H), + .step = 1, + .def = 0, +}; + +static int npcm_video_open(struct file *file) +{ + struct npcm_video *video = video_drvdata(file); + int rc; + + mutex_lock(&video->video_lock); + rc = v4l2_fh_open(file); + if (rc) { + mutex_unlock(&video->video_lock); + return rc; + } + + if (v4l2_fh_is_singular_file(file)) + npcm_video_start(video); + + mutex_unlock(&video->video_lock); + return 0; +} + +static int npcm_video_release(struct file *file) +{ + struct npcm_video *video = video_drvdata(file); + int rc; + + mutex_lock(&video->video_lock); + if (v4l2_fh_is_singular_file(file)) + npcm_video_stop(video); + + rc = _vb2_fop_release(file, NULL); + + mutex_unlock(&video->video_lock); + return rc; +} + +static const struct v4l2_file_operations npcm_video_v4l2_fops = { + .owner = THIS_MODULE, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, + .open = npcm_video_open, + .release = npcm_video_release, +}; + +static int npcm_video_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct npcm_video *video = vb2_get_drv_priv(q); + unsigned int i; + + if (*num_planes) { + if (sizes[0] < video->pix_fmt.sizeimage) + return -EINVAL; + + return 0; + } + + *num_planes = 1; + sizes[0] = video->pix_fmt.sizeimage; + + for (i = 0; i < VIDEO_MAX_FRAME; i++) + INIT_LIST_HEAD(&video->list[i]); + + return 0; +} + +static int npcm_video_buf_prepare(struct vb2_buffer *vb) +{ + struct npcm_video *video = vb2_get_drv_priv(vb->vb2_queue); + + if (vb2_plane_size(vb, 0) < video->pix_fmt.sizeimage) + return -EINVAL; + + return 0; +} + +static int npcm_video_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct npcm_video *video = vb2_get_drv_priv(q); + int rc; + + video->sequence = 0; + rc = npcm_video_start_frame(video); + if (rc) { + npcm_video_bufs_done(video, VB2_BUF_STATE_QUEUED); + return rc; + } + + set_bit(VIDEO_STREAMING, &video->flags); + return 0; +} + +static void npcm_video_stop_streaming(struct vb2_queue *q) +{ + struct npcm_video *video = vb2_get_drv_priv(q); + struct regmap *vcd = video->vcd_regmap; + + clear_bit(VIDEO_STREAMING, &video->flags); + regmap_write(vcd, VCD_INTE, 0); + regmap_write(vcd, VCD_STAT, VCD_STAT_CLEAR); + npcm_video_gfx_reset(video); + npcm_video_bufs_done(video, VB2_BUF_STATE_ERROR); + video->ctrl_cmd = VCD_CMD_OPERATION_CAPTURE; + v4l2_ctrl_s_ctrl(video->rect_cnt_ctrl, 0); +} + +static void npcm_video_buf_queue(struct vb2_buffer *vb) +{ + struct npcm_video *video = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct npcm_video_buffer *nvb = to_npcm_video_buffer(vbuf); + unsigned long flags; + bool empty; + + spin_lock_irqsave(&video->lock, flags); + empty = list_empty(&video->buffers); + list_add_tail(&nvb->link, &video->buffers); + spin_unlock_irqrestore(&video->lock, flags); + + if (test_bit(VIDEO_STREAMING, &video->flags) && + !test_bit(VIDEO_CAPTURING, &video->flags) && empty) { + if (npcm_video_start_frame(video)) + dev_err(video->dev, "Failed to capture next frame\n"); + } +} + +static void npcm_video_buf_finish(struct vb2_buffer *vb) +{ + struct npcm_video *video = vb2_get_drv_priv(vb->vb2_queue); + struct list_head *head, *pos, *nx; + struct rect_list *tmp; + + /* + * This callback is called when the buffer is dequeued, so update + * V4L2_CID_NPCM_RECT_COUNT control value with the number of rectangles + * in this buffer and free associated rect_list. + */ + if (test_bit(VIDEO_STREAMING, &video->flags)) { + v4l2_ctrl_s_ctrl(video->rect_cnt_ctrl, video->rect[vb->index]); + + head = &video->list[vb->index]; + list_for_each_safe(pos, nx, head) { + tmp = list_entry(pos, struct rect_list, list); + list_del(&tmp->list); + kfree(tmp); + } + } +} + +static const struct regmap_config npcm_video_regmap_cfg = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = VCD_FIFO, +}; + +static const struct regmap_config npcm_video_ece_regmap_cfg = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = ECE_HEX_RECT_OFFSET, +}; + +static const struct vb2_ops npcm_video_vb2_ops = { + .queue_setup = npcm_video_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_prepare = npcm_video_buf_prepare, + .buf_finish = npcm_video_buf_finish, + .start_streaming = npcm_video_start_streaming, + .stop_streaming = npcm_video_stop_streaming, + .buf_queue = npcm_video_buf_queue, +}; + +static int npcm_video_setup_video(struct npcm_video *video) +{ + struct v4l2_device *v4l2_dev = &video->v4l2_dev; + struct video_device *vdev = &video->vdev; + struct vb2_queue *vbq = &video->queue; + int rc; + + if (video->ece.enable) + video->pix_fmt.pixelformat = V4L2_PIX_FMT_HEXTILE; + else + video->pix_fmt.pixelformat = V4L2_PIX_FMT_RGB565; + + video->pix_fmt.field = V4L2_FIELD_NONE; + video->pix_fmt.colorspace = V4L2_COLORSPACE_SRGB; + video->pix_fmt.quantization = V4L2_QUANTIZATION_FULL_RANGE; + video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; + + rc = v4l2_device_register(video->dev, v4l2_dev); + if (rc) { + dev_err(video->dev, "Failed to register v4l2 device\n"); + return rc; + } + + v4l2_ctrl_handler_init(&video->ctrl_handler, 2); + v4l2_ctrl_new_custom(&video->ctrl_handler, &npcm_ctrl_capture_mode, NULL); + video->rect_cnt_ctrl = v4l2_ctrl_new_custom(&video->ctrl_handler, + &npcm_ctrl_rect_count, NULL); + if (video->ctrl_handler.error) { + dev_err(video->dev, "Failed to init controls: %d\n", + video->ctrl_handler.error); + + rc = video->ctrl_handler.error; + goto rel_ctrl_handler; + } + v4l2_dev->ctrl_handler = &video->ctrl_handler; + + vbq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vbq->io_modes = VB2_MMAP | VB2_DMABUF; + vbq->dev = v4l2_dev->dev; + vbq->lock = &video->video_lock; + vbq->ops = &npcm_video_vb2_ops; + vbq->mem_ops = &vb2_dma_contig_memops; + vbq->drv_priv = video; + vbq->buf_struct_size = sizeof(struct npcm_video_buffer); + vbq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vbq->min_buffers_needed = 3; + + rc = vb2_queue_init(vbq); + if (rc) { + dev_err(video->dev, "Failed to init vb2 queue\n"); + goto rel_ctrl_handler; + } + vdev->queue = vbq; + vdev->fops = &npcm_video_v4l2_fops; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + vdev->v4l2_dev = v4l2_dev; + strscpy(vdev->name, DEVICE_NAME, sizeof(vdev->name)); + vdev->vfl_type = VFL_TYPE_VIDEO; + vdev->vfl_dir = VFL_DIR_RX; + vdev->release = video_device_release_empty; + vdev->ioctl_ops = &npcm_video_ioctls; + vdev->lock = &video->video_lock; + + video_set_drvdata(vdev, video); + rc = video_register_device(vdev, VFL_TYPE_VIDEO, 0); + if (rc) { + dev_err(video->dev, "Failed to register video device\n"); + goto rel_vb_queue; + } + + return 0; + +rel_vb_queue: + vb2_queue_release(vbq); +rel_ctrl_handler: + v4l2_ctrl_handler_free(&video->ctrl_handler); + v4l2_device_unregister(v4l2_dev); + + return rc; +} + +static int npcm_video_ece_init(struct npcm_video *video) +{ + struct device *dev = video->dev; + struct device_node *ece_node; + struct platform_device *ece_pdev; + void __iomem *regs; + + ece_node = of_parse_phandle(video->dev->of_node, "nuvoton,ece", 0); + if (IS_ERR(ece_node)) { + dev_err(dev, "Failed to get ECE phandle in DTS\n"); + return PTR_ERR(ece_node); + } + + video->ece.enable = of_device_is_available(ece_node); + + if (video->ece.enable) { + dev_info(dev, "Support HEXTILE pixel format\n"); + + ece_pdev = of_find_device_by_node(ece_node); + if (IS_ERR(ece_pdev)) { + dev_err(dev, "Failed to find ECE device\n"); + return PTR_ERR(ece_pdev); + } + of_node_put(ece_node); + + regs = devm_platform_ioremap_resource(ece_pdev, 0); + if (IS_ERR(regs)) { + dev_err(dev, "Failed to parse ECE reg in DTS\n"); + return PTR_ERR(regs); + } + + video->ece.regmap = devm_regmap_init_mmio(dev, regs, + &npcm_video_ece_regmap_cfg); + if (IS_ERR(video->ece.regmap)) { + dev_err(dev, "Failed to initialize ECE regmap\n"); + return PTR_ERR(video->ece.regmap); + } + + video->ece.reset = devm_reset_control_get(&ece_pdev->dev, NULL); + if (IS_ERR(video->ece.reset)) { + dev_err(dev, "Failed to get ECE reset control in DTS\n"); + return PTR_ERR(video->ece.reset); + } + } + + return 0; +} + +static int npcm_video_init(struct npcm_video *video) +{ + struct device *dev = video->dev; + int irq, rc; + + irq = irq_of_parse_and_map(dev->of_node, 0); + if (!irq) { + dev_err(dev, "Failed to find VCD IRQ\n"); + return -ENODEV; + } + + rc = devm_request_threaded_irq(dev, irq, NULL, npcm_video_irq, + IRQF_ONESHOT, DEVICE_NAME, video); + if (rc < 0) { + dev_err(dev, "Failed to request IRQ %d\n", irq); + return rc; + } + + of_reserved_mem_device_init(dev); + rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (rc) { + dev_err(dev, "Failed to set DMA mask\n"); + of_reserved_mem_device_release(dev); + } + + rc = npcm_video_ece_init(video); + if (rc) { + dev_err(dev, "Failed to initialize ECE\n"); + return rc; + } + + return 0; +} + +static int npcm_video_probe(struct platform_device *pdev) +{ + struct npcm_video *video = kzalloc(sizeof(*video), GFP_KERNEL); + int rc; + void __iomem *regs; + + if (!video) + return -ENOMEM; + + video->dev = &pdev->dev; + spin_lock_init(&video->lock); + mutex_init(&video->video_lock); + INIT_LIST_HEAD(&video->buffers); + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) { + dev_err(&pdev->dev, "Failed to parse VCD reg in DTS\n"); + return PTR_ERR(regs); + } + + video->vcd_regmap = devm_regmap_init_mmio(&pdev->dev, regs, + &npcm_video_regmap_cfg); + if (IS_ERR(video->vcd_regmap)) { + dev_err(&pdev->dev, "Failed to initialize VCD regmap\n"); + return PTR_ERR(video->vcd_regmap); + } + + video->reset = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(video->reset)) { + dev_err(&pdev->dev, "Failed to get VCD reset control in DTS\n"); + return PTR_ERR(video->reset); + } + + video->gcr_regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "nuvoton,sysgcr"); + if (IS_ERR(video->gcr_regmap)) + return PTR_ERR(video->gcr_regmap); + + video->gfx_regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "nuvoton,sysgfxi"); + if (IS_ERR(video->gfx_regmap)) + return PTR_ERR(video->gfx_regmap); + + rc = npcm_video_init(video); + if (rc) + return rc; + + rc = npcm_video_setup_video(video); + if (rc) + return rc; + + dev_info(video->dev, "NPCM video driver probed\n"); + return 0; +} + +static int npcm_video_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); + struct npcm_video *video = to_npcm_video(v4l2_dev); + + video_unregister_device(&video->vdev); + vb2_queue_release(&video->queue); + v4l2_ctrl_handler_free(&video->ctrl_handler); + v4l2_device_unregister(v4l2_dev); + if (video->ece.enable) + npcm_video_ece_stop(video); + of_reserved_mem_device_release(dev); + + return 0; +} + +static const struct of_device_id npcm_video_match[] = { + { .compatible = "nuvoton,npcm750-vcd" }, + { .compatible = "nuvoton,npcm845-vcd" }, + {}, +}; + +MODULE_DEVICE_TABLE(of, npcm_video_match); + +static struct platform_driver npcm_video_driver = { + .driver = { + .name = DEVICE_NAME, + .of_match_table = npcm_video_match, + }, + .probe = npcm_video_probe, + .remove = npcm_video_remove, +}; + +module_platform_driver(npcm_video_driver); + +MODULE_AUTHOR("Joseph Liu "); +MODULE_AUTHOR("Marvin Lin "); +MODULE_DESCRIPTION("Driver for Nuvoton NPCM Video Capture/Encode Engine"); +MODULE_LICENSE("GPL v2"); -- GitLab From da923feefead2efc05ef21eb2a3f1058fe4c13ae Mon Sep 17 00:00:00 2001 From: Sean Young Date: Fri, 1 Sep 2023 15:18:55 +0100 Subject: [PATCH 0320/1451] dt-bindings: media: remove nokia,n900-ir as pwm-ir-tx is compatible The generic pwm-ir-tx driver works for the Nokia n900, so nokia,n900-ir can be removed. Acked-by: Conor Dooley Acked-by: Lee Jones Signed-off-by: Sean Young Signed-off-by: Hans Verkuil --- .../bindings/leds/irled/pwm-ir-tx.yaml | 5 ++++- .../devicetree/bindings/media/nokia,n900-ir | 20 ------------------- 2 files changed, 4 insertions(+), 21 deletions(-) delete mode 100644 Documentation/devicetree/bindings/media/nokia,n900-ir diff --git a/Documentation/devicetree/bindings/leds/irled/pwm-ir-tx.yaml b/Documentation/devicetree/bindings/leds/irled/pwm-ir-tx.yaml index f2a6fa140f38c..7526e3149f728 100644 --- a/Documentation/devicetree/bindings/leds/irled/pwm-ir-tx.yaml +++ b/Documentation/devicetree/bindings/leds/irled/pwm-ir-tx.yaml @@ -15,7 +15,10 @@ description: properties: compatible: - const: pwm-ir-tx + oneOf: + - const: pwm-ir-tx + - const: nokia,n900-ir + deprecated: true pwms: maxItems: 1 diff --git a/Documentation/devicetree/bindings/media/nokia,n900-ir b/Documentation/devicetree/bindings/media/nokia,n900-ir deleted file mode 100644 index 13a18ce37dd14..0000000000000 --- a/Documentation/devicetree/bindings/media/nokia,n900-ir +++ /dev/null @@ -1,20 +0,0 @@ -Device-Tree bindings for LIRC TX driver for Nokia N900(RX51) - -Required properties: - - compatible: should be "nokia,n900-ir". - - pwms: specifies PWM used for IR signal transmission. - -Example node: - - pwm9: dmtimer-pwm@9 { - compatible = "ti,omap-dmtimer-pwm"; - ti,timers = <&timer9>; - ti,clock-source = <0x00>; /* timer_sys_ck */ - #pwm-cells = <3>; - }; - - ir: n900-ir { - compatible = "nokia,n900-ir"; - - pwms = <&pwm9 0 26316 0>; /* 38000 Hz */ - }; -- GitLab From 5ce19a501673b72cf57ce1908a29a3c5b3cd30bb Mon Sep 17 00:00:00 2001 From: Sean Young Date: Fri, 1 Sep 2023 15:18:56 +0100 Subject: [PATCH 0321/1451] media: rc: remove ir-rx51 in favour of generic pwm-ir-tx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ir-rx51 is a pwm-based TX driver specific to the N900. This can be handled entirely by the generic pwm-ir-tx driver, and in fact the pwm-ir-tx driver has been compatible with ir-rx51 from the start. Note that the suspend code in the ir-rx51 driver is unnecessary, since during transmit, the process is not in interruptable sleep. The process is not put to sleep until the transmit completes. Acked-by: Uwe Kleine-König Tested-by: Sicelo A. Mhlongo Signed-off-by: Sean Young Signed-off-by: Hans Verkuil --- arch/arm/configs/omap2plus_defconfig | 1 - drivers/media/rc/Kconfig | 10 - drivers/media/rc/Makefile | 1 - drivers/media/rc/ir-rx51.c | 285 --------------------------- drivers/media/rc/pwm-ir-tx.c | 1 + 5 files changed, 1 insertion(+), 297 deletions(-) delete mode 100644 drivers/media/rc/ir-rx51.c diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index b685018dcf54b..ef39ab57b75aa 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -484,7 +484,6 @@ CONFIG_LIRC=y CONFIG_RC_DEVICES=y CONFIG_IR_GPIO_TX=m CONFIG_IR_PWM_TX=m -CONFIG_IR_RX51=m CONFIG_IR_SPI=m CONFIG_MEDIA_SUPPORT=m CONFIG_V4L_PLATFORM_DRIVERS=y diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 07bdf649c60dc..2afe67ffa285e 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -338,16 +338,6 @@ config IR_REDRAT3 To compile this driver as a module, choose M here: the module will be called redrat3. -config IR_RX51 - tristate "Nokia N900 IR transmitter diode" - depends on (OMAP_DM_TIMER && PWM_OMAP_DMTIMER && ARCH_OMAP2PLUS || COMPILE_TEST) && RC_CORE - help - Say Y or M here if you want to enable support for the IR - transmitter diode built in the Nokia N900 (RX51) device. - - The driver uses omap DM timers for generating the carrier - wave and pulses. - config IR_SERIAL tristate "Homebrew Serial Port Receiver" depends on HAS_IOPORT diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index a9285266e9447..2bca6f7f07bc9 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -43,7 +43,6 @@ obj-$(CONFIG_IR_MTK) += mtk-cir.o obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o obj-$(CONFIG_IR_PWM_TX) += pwm-ir-tx.o obj-$(CONFIG_IR_REDRAT3) += redrat3.o -obj-$(CONFIG_IR_RX51) += ir-rx51.o obj-$(CONFIG_IR_SERIAL) += serial_ir.o obj-$(CONFIG_IR_SPI) += ir-spi.o obj-$(CONFIG_IR_STREAMZAP) += streamzap.o diff --git a/drivers/media/rc/ir-rx51.c b/drivers/media/rc/ir-rx51.c deleted file mode 100644 index 13e81bf8005df..0000000000000 --- a/drivers/media/rc/ir-rx51.c +++ /dev/null @@ -1,285 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2008 Nokia Corporation - * - * Based on lirc_serial.c - */ -#include -#include -#include -#include -#include -#include -#include - -#include - -#define WBUF_LEN 256 - -struct ir_rx51 { - struct rc_dev *rcdev; - struct pwm_device *pwm; - struct pwm_state state; - struct hrtimer timer; - struct device *dev; - wait_queue_head_t wqueue; - - unsigned int freq; /* carrier frequency */ - unsigned int duty_cycle; /* carrier duty cycle */ - int wbuf[WBUF_LEN]; - int wbuf_index; - unsigned long device_is_open; -}; - -static inline void ir_rx51_on(struct ir_rx51 *ir_rx51) -{ - ir_rx51->state.enabled = true; - pwm_apply_state(ir_rx51->pwm, &ir_rx51->state); -} - -static inline void ir_rx51_off(struct ir_rx51 *ir_rx51) -{ - ir_rx51->state.enabled = false; - pwm_apply_state(ir_rx51->pwm, &ir_rx51->state); -} - -static int init_timing_params(struct ir_rx51 *ir_rx51) -{ - ir_rx51->state.period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, ir_rx51->freq); - pwm_set_relative_duty_cycle(&ir_rx51->state, ir_rx51->duty_cycle, 100); - - return 0; -} - -static enum hrtimer_restart ir_rx51_timer_cb(struct hrtimer *timer) -{ - struct ir_rx51 *ir_rx51 = container_of(timer, struct ir_rx51, timer); - ktime_t now; - - if (ir_rx51->wbuf_index < 0) { - dev_err_ratelimited(ir_rx51->dev, - "BUG wbuf_index has value of %i\n", - ir_rx51->wbuf_index); - goto end; - } - - /* - * If we happen to hit an odd latency spike, loop through the - * pulses until we catch up. - */ - do { - u64 ns; - - if (ir_rx51->wbuf_index >= WBUF_LEN) - goto end; - if (ir_rx51->wbuf[ir_rx51->wbuf_index] == -1) - goto end; - - if (ir_rx51->wbuf_index % 2) - ir_rx51_off(ir_rx51); - else - ir_rx51_on(ir_rx51); - - ns = US_TO_NS(ir_rx51->wbuf[ir_rx51->wbuf_index]); - hrtimer_add_expires_ns(timer, ns); - - ir_rx51->wbuf_index++; - - now = timer->base->get_time(); - - } while (hrtimer_get_expires_tv64(timer) < now); - - return HRTIMER_RESTART; -end: - /* Stop TX here */ - ir_rx51_off(ir_rx51); - ir_rx51->wbuf_index = -1; - - wake_up_interruptible(&ir_rx51->wqueue); - - return HRTIMER_NORESTART; -} - -static int ir_rx51_tx(struct rc_dev *dev, unsigned int *buffer, - unsigned int count) -{ - struct ir_rx51 *ir_rx51 = dev->priv; - - if (count > WBUF_LEN) - return -EINVAL; - - memcpy(ir_rx51->wbuf, buffer, count * sizeof(unsigned int)); - - /* Wait any pending transfers to finish */ - wait_event_interruptible(ir_rx51->wqueue, ir_rx51->wbuf_index < 0); - - init_timing_params(ir_rx51); - if (count < WBUF_LEN) - ir_rx51->wbuf[count] = -1; /* Insert termination mark */ - - /* - * REVISIT: Adjust latency requirements so the device doesn't go in too - * deep sleep states with pm_qos_add_request(). - */ - - ir_rx51_on(ir_rx51); - ir_rx51->wbuf_index = 1; - hrtimer_start(&ir_rx51->timer, - ns_to_ktime(US_TO_NS(ir_rx51->wbuf[0])), - HRTIMER_MODE_REL); - /* - * Don't return back to the userspace until the transfer has - * finished - */ - wait_event_interruptible(ir_rx51->wqueue, ir_rx51->wbuf_index < 0); - - /* REVISIT: Remove pm_qos constraint, we can sleep again */ - - return count; -} - -static int ir_rx51_open(struct rc_dev *dev) -{ - struct ir_rx51 *ir_rx51 = dev->priv; - - if (test_and_set_bit(1, &ir_rx51->device_is_open)) - return -EBUSY; - - ir_rx51->pwm = pwm_get(ir_rx51->dev, NULL); - if (IS_ERR(ir_rx51->pwm)) { - int res = PTR_ERR(ir_rx51->pwm); - - dev_err(ir_rx51->dev, "pwm_get failed: %d\n", res); - return res; - } - - return 0; -} - -static void ir_rx51_release(struct rc_dev *dev) -{ - struct ir_rx51 *ir_rx51 = dev->priv; - - hrtimer_cancel(&ir_rx51->timer); - ir_rx51_off(ir_rx51); - pwm_put(ir_rx51->pwm); - - clear_bit(1, &ir_rx51->device_is_open); -} - -static struct ir_rx51 ir_rx51 = { - .duty_cycle = 50, - .wbuf_index = -1, -}; - -static int ir_rx51_set_duty_cycle(struct rc_dev *dev, u32 duty) -{ - struct ir_rx51 *ir_rx51 = dev->priv; - - ir_rx51->duty_cycle = duty; - - return 0; -} - -static int ir_rx51_set_tx_carrier(struct rc_dev *dev, u32 carrier) -{ - struct ir_rx51 *ir_rx51 = dev->priv; - - if (carrier > 500000 || carrier < 20000) - return -EINVAL; - - ir_rx51->freq = carrier; - - return 0; -} - -#ifdef CONFIG_PM - -static int ir_rx51_suspend(struct platform_device *dev, pm_message_t state) -{ - /* - * In case the device is still open, do not suspend. Normally - * this should not be a problem as lircd only keeps the device - * open only for short periods of time. We also don't want to - * get involved with race conditions that might happen if we - * were in a middle of a transmit. Thus, we defer any suspend - * actions until transmit has completed. - */ - if (test_and_set_bit(1, &ir_rx51.device_is_open)) - return -EAGAIN; - - clear_bit(1, &ir_rx51.device_is_open); - - return 0; -} - -static int ir_rx51_resume(struct platform_device *dev) -{ - return 0; -} - -#else - -#define ir_rx51_suspend NULL -#define ir_rx51_resume NULL - -#endif /* CONFIG_PM */ - -static int ir_rx51_probe(struct platform_device *dev) -{ - struct pwm_device *pwm; - struct rc_dev *rcdev; - - pwm = pwm_get(&dev->dev, NULL); - if (IS_ERR(pwm)) - return dev_err_probe(&dev->dev, PTR_ERR(pwm), "pwm_get failed\n"); - - /* Use default, in case userspace does not set the carrier */ - ir_rx51.freq = DIV_ROUND_CLOSEST_ULL(pwm_get_period(pwm), NSEC_PER_SEC); - pwm_init_state(pwm, &ir_rx51.state); - pwm_put(pwm); - - hrtimer_init(&ir_rx51.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - ir_rx51.timer.function = ir_rx51_timer_cb; - - ir_rx51.dev = &dev->dev; - - rcdev = devm_rc_allocate_device(&dev->dev, RC_DRIVER_IR_RAW_TX); - if (!rcdev) - return -ENOMEM; - - rcdev->priv = &ir_rx51; - rcdev->open = ir_rx51_open; - rcdev->close = ir_rx51_release; - rcdev->tx_ir = ir_rx51_tx; - rcdev->s_tx_duty_cycle = ir_rx51_set_duty_cycle; - rcdev->s_tx_carrier = ir_rx51_set_tx_carrier; - rcdev->driver_name = KBUILD_MODNAME; - - ir_rx51.rcdev = rcdev; - - return devm_rc_register_device(&dev->dev, ir_rx51.rcdev); -} - -static const struct of_device_id ir_rx51_match[] = { - { - .compatible = "nokia,n900-ir", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, ir_rx51_match); - -static struct platform_driver ir_rx51_platform_driver = { - .probe = ir_rx51_probe, - .suspend = ir_rx51_suspend, - .resume = ir_rx51_resume, - .driver = { - .name = KBUILD_MODNAME, - .of_match_table = ir_rx51_match, - }, -}; -module_platform_driver(ir_rx51_platform_driver); - -MODULE_DESCRIPTION("IR TX driver for Nokia RX51"); -MODULE_AUTHOR("Nokia Corporation"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/rc/pwm-ir-tx.c b/drivers/media/rc/pwm-ir-tx.c index 7732054c4621e..c5f37c03af9c9 100644 --- a/drivers/media/rc/pwm-ir-tx.c +++ b/drivers/media/rc/pwm-ir-tx.c @@ -23,6 +23,7 @@ struct pwm_ir { static const struct of_device_id pwm_ir_of_match[] = { { .compatible = "pwm-ir-tx", }, + { .compatible = "nokia,n900-ir" }, { }, }; MODULE_DEVICE_TABLE(of, pwm_ir_of_match); -- GitLab From e798f5b2d1cc22c6a01107da504dd195e685339c Mon Sep 17 00:00:00 2001 From: Zelong Dong Date: Fri, 25 Aug 2023 19:53:08 +0800 Subject: [PATCH 0322/1451] media: rc: meson-ir: support rc driver type RC_DRIVER_SCANCODE Meson IR Controller supports hardware decoder in Meson-S4 and later SoC. So far, protocol NEC could be decoded by hardware decoder. Signed-off-by: Zelong Dong Reviewed-by: Neil Armstrong Signed-off-by: Sean Young Signed-off-by: Hans Verkuil --- drivers/media/rc/meson-ir.c | 522 +++++++++++++++++++++++++++++++----- 1 file changed, 451 insertions(+), 71 deletions(-) diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c index 70322fab34ac3..5303e6da58095 100644 --- a/drivers/media/rc/meson-ir.c +++ b/drivers/media/rc/meson-ir.c @@ -20,48 +20,196 @@ #define DRIVER_NAME "meson-ir" -#define IR_DEC_LDR_ACTIVE 0x00 -#define IR_DEC_LDR_IDLE 0x04 -#define IR_DEC_LDR_REPEAT 0x08 -#define IR_DEC_BIT_0 0x0c -#define IR_DEC_REG0 0x10 -#define IR_DEC_REG0_BASE_TIME GENMASK(11, 0) -#define IR_DEC_FRAME 0x14 -#define IR_DEC_STATUS 0x18 -#define IR_DEC_STATUS_PULSE BIT(8) -#define IR_DEC_REG1 0x1c -#define IR_DEC_REG1_TIME_IV GENMASK(28, 16) -#define IR_DEC_REG1_ENABLE BIT(15) -#define IR_DEC_REG1_MODE GENMASK(8, 7) -#define IR_DEC_REG1_IRQSEL GENMASK(3, 2) -#define IR_DEC_REG1_RESET BIT(0) -/* The following regs are only available on Meson 8b and newer */ -#define IR_DEC_REG2 0x20 -#define IR_DEC_REG2_MODE GENMASK(3, 0) - -#define DEC_MODE_NEC 0x0 -#define DEC_MODE_RAW 0x2 - -#define IRQSEL_NEC_MODE 0 -#define IRQSEL_RISE_FALL 1 -#define IRQSEL_FALL 2 -#define IRQSEL_RISE 3 - -#define MESON_RAW_TRATE 10 /* us */ -#define MESON_HW_TRATE 20 /* us */ +#define IR_DEC_LDR_ACTIVE 0x00 +#define IR_DEC_LDR_ACTIVE_MAX GENMASK(28, 16) +#define IR_DEC_LDR_ACTIVE_MIN GENMASK(12, 0) +#define IR_DEC_LDR_IDLE 0x04 +#define IR_DEC_LDR_IDLE_MAX GENMASK(28, 16) +#define IR_DEC_LDR_IDLE_MIN GENMASK(12, 0) +#define IR_DEC_LDR_REPEAT 0x08 +#define IR_DEC_LDR_REPEAT_MAX GENMASK(25, 16) +#define IR_DEC_LDR_REPEAT_MIN GENMASK(9, 0) +#define IR_DEC_BIT_0 0x0c +#define IR_DEC_BIT_0_MAX GENMASK(25, 16) +#define IR_DEC_BIT_0_MIN GENMASK(9, 0) +#define IR_DEC_REG0 0x10 +#define IR_DEC_REG0_FILTER GENMASK(30, 28) +#define IR_DEC_REG0_FRAME_TIME_MAX GENMASK(24, 12) +#define IR_DEC_REG0_BASE_TIME GENMASK(11, 0) +#define IR_DEC_FRAME 0x14 +#define IR_DEC_STATUS 0x18 +#define IR_DEC_STATUS_BIT_1_ENABLE BIT(30) +#define IR_DEC_STATUS_BIT_1_MAX GENMASK(29, 20) +#define IR_DEC_STATUS_BIT_1_MIN GENMASK(19, 10) +#define IR_DEC_STATUS_PULSE BIT(8) +#define IR_DEC_STATUS_BUSY BIT(7) +#define IR_DEC_STATUS_FRAME_STATUS GENMASK(3, 0) +#define IR_DEC_REG1 0x1c +#define IR_DEC_REG1_TIME_IV GENMASK(28, 16) +#define IR_DEC_REG1_FRAME_LEN GENMASK(13, 8) +#define IR_DEC_REG1_ENABLE BIT(15) +#define IR_DEC_REG1_HOLD_CODE BIT(6) +#define IR_DEC_REG1_IRQSEL GENMASK(3, 2) +#define IR_DEC_REG1_RESET BIT(0) +/* Meson 6b uses REG1 to configure IR mode */ +#define IR_DEC_REG1_MODE GENMASK(8, 7) + +/* The following registers are only available on Meson 8b and newer */ +#define IR_DEC_REG2 0x20 +#define IR_DEC_REG2_TICK_MODE BIT(15) +#define IR_DEC_REG2_REPEAT_COUNTER BIT(13) +#define IR_DEC_REG2_REPEAT_TIME BIT(12) +#define IR_DEC_REG2_COMPARE_FRAME BIT(11) +#define IR_DEC_REG2_BIT_ORDER BIT(8) +/* Meson 8b / GXBB use REG2 to configure IR mode */ +#define IR_DEC_REG2_MODE GENMASK(3, 0) +#define IR_DEC_DURATN2 0x24 +#define IR_DEC_DURATN2_MAX GENMASK(25, 16) +#define IR_DEC_DURATN2_MIN GENMASK(9, 0) +#define IR_DEC_DURATN3 0x28 +#define IR_DEC_DURATN3_MAX GENMASK(25, 16) +#define IR_DEC_DURATN3_MIN GENMASK(9, 0) +#define IR_DEC_FRAME1 0x2c + +#define FRAME_MSB_FIRST true +#define FRAME_LSB_FIRST false + +#define DEC_MODE_NEC 0x0 +#define DEC_MODE_RAW 0x2 +#define DEC_MODE_RC6 0x9 +#define DEC_MODE_XMP 0xE +#define DEC_MODE_UNKNOW 0xFF + +#define DEC_STATUS_VALID BIT(3) +#define DEC_STATUS_DATA_CODE_ERR BIT(2) +#define DEC_STATUS_CUSTOM_CODE_ERR BIT(1) +#define DEC_STATUS_REPEAT BIT(0) + +#define IRQSEL_DEC_MODE 0 +#define IRQSEL_RISE_FALL 1 +#define IRQSEL_FALL 2 +#define IRQSEL_RISE 3 + +#define MESON_RAW_TRATE 10 /* us */ +#define MESON_HW_TRATE 20 /* us */ + +/** + * struct meson_ir_protocol - describe IR Protocol parameter + * + * @hw_protocol: select IR Protocol from IR Controller + * @repeat_counter_enable: enable frame-to-frame time counter, it should work + * with @repeat_compare_enable to detect the repeat frame + * @repeat_check_enable: enable repeat time check for repeat detection + * @repeat_compare_enable: enable to compare frame for repeat frame detection. + * Some IR Protocol send the same data as repeat frame. + * In this case, it should work with + * @repeat_counter_enable to detect the repeat frame. + * @bit_order: bit order, LSB or MSB + * @bit1_match_enable: enable to check bit 1 + * @hold_code_enable: hold frame code in register IR_DEC_FRAME1, the new one + * frame code will not be store in IR_DEC_FRAME1. + * until IR_DEC_FRAME1 has been read + * @count_tick_mode: increasing time unit of frame-to-frame time counter. + * 0 = 100us, 1 = 10us + * @code_length: length (N-1) of data frame + * @frame_time_max: max time for whole frame. Unit: MESON_HW_TRATE + * @leader_active_max: max time for NEC/RC6 leader active part. Unit: MESON_HW_TRATE + * @leader_active_min: min time for NEC/RC6 leader active part. Unit: MESON_HW_TRATE + * @leader_idle_max: max time for NEC/RC6 leader idle part. Unit: MESON_HW_TRATE + * @leader_idle_min: min time for NEC/RC6 leader idle part. Unit: MESON_HW_TRATE + * @repeat_leader_max: max time for NEC repeat leader idle part. Unit: MESON_HW_TRATE + * @repeat_leader_min: min time for NEC repeat leader idle part. Unit: MESON_HW_TRATE + * @bit0_max: max time for NEC Logic '0', half of RC6 trailer bit, XMP Logic '00' + * @bit0_min: min time for NEC Logic '0', half of RC6 trailer bit, XMP Logic '00' + * @bit1_max: max time for NEC Logic '1', whole of RC6 trailer bit, XMP Logic '01' + * @bit1_min: min time for NEC Logic '1', whole of RC6 trailer bit, XMP Logic '01' + * @duration2_max: max time for half of RC6 normal bit, XMP Logic '10' + * @duration2_min: min time for half of RC6 normal bit, XMP Logic '10' + * @duration3_max: max time for whole of RC6 normal bit, XMP Logic '11' + * @duration3_min: min time for whole of RC6 normal bit, XMP Logic '11' + */ + +struct meson_ir_protocol { + u8 hw_protocol; + bool repeat_counter_enable; + bool repeat_check_enable; + bool repeat_compare_enable; + bool bit_order; + bool bit1_match_enable; + bool hold_code_enable; + bool count_tick_mode; + u8 code_length; + u16 frame_time_max; + u16 leader_active_max; + u16 leader_active_min; + u16 leader_idle_max; + u16 leader_idle_min; + u16 repeat_leader_max; + u16 repeat_leader_min; + u16 bit0_max; + u16 bit0_min; + u16 bit1_max; + u16 bit1_min; + u16 duration2_max; + u16 duration2_min; + u16 duration3_max; + u16 duration3_min; +}; + +struct meson_ir_param { + bool support_hw_decoder; + unsigned int max_register; +}; struct meson_ir { + const struct meson_ir_param *param; struct regmap *reg; struct rc_dev *rc; spinlock_t lock; }; -static const struct regmap_config meson_ir_regmap_config = { +static struct regmap_config meson_ir_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, }; +static const struct meson_ir_protocol protocol_timings[] = { + /* protocol, repeat counter, repeat check, repeat compare, order */ + {DEC_MODE_NEC, false, false, false, FRAME_LSB_FIRST, + /* bit 1 match, hold code, count tick, len, frame time */ + true, false, false, 32, 4000, + /* leader active max/min, leader idle max/min, repeat leader max/min */ + 500, 400, 300, 200, 150, 80, + /* bit0 max/min, bit1 max/min, duration2 max/min, duration3 max/min */ + 72, 40, 134, 90, 0, 0, 0, 0} +}; + +static void meson_ir_nec_handler(struct meson_ir *ir) +{ + u32 code = 0; + u32 status = 0; + enum rc_proto proto; + + regmap_read(ir->reg, IR_DEC_STATUS, &status); + + if (status & DEC_STATUS_REPEAT) { + rc_repeat(ir->rc); + } else { + regmap_read(ir->reg, IR_DEC_FRAME, &code); + + code = ir_nec_bytes_to_scancode(code, code >> 8, + code >> 16, code >> 24, &proto); + rc_keydown(ir->rc, proto, code, 0); + } +} + +static void meson_ir_hw_handler(struct meson_ir *ir) +{ + if (ir->rc->enabled_protocols & RC_PROTO_BIT_NEC) + meson_ir_nec_handler(ir); +} + static irqreturn_t meson_ir_irq(int irqno, void *dev_id) { struct meson_ir *ir = dev_id; @@ -70,22 +218,232 @@ static irqreturn_t meson_ir_irq(int irqno, void *dev_id) spin_lock(&ir->lock); - regmap_read(ir->reg, IR_DEC_REG1, &duration); - duration = FIELD_GET(IR_DEC_REG1_TIME_IV, duration); - rawir.duration = duration * MESON_RAW_TRATE; - regmap_read(ir->reg, IR_DEC_STATUS, &status); - rawir.pulse = !!(status & IR_DEC_STATUS_PULSE); - ir_raw_event_store_with_timeout(ir->rc, &rawir); + if (ir->rc->driver_type == RC_DRIVER_IR_RAW) { + rawir.pulse = !!(status & IR_DEC_STATUS_PULSE); + + regmap_read(ir->reg, IR_DEC_REG1, &duration); + duration = FIELD_GET(IR_DEC_REG1_TIME_IV, duration); + rawir.duration = duration * MESON_RAW_TRATE; + + ir_raw_event_store_with_timeout(ir->rc, &rawir); + } else if (ir->rc->driver_type == RC_DRIVER_SCANCODE) { + if (status & DEC_STATUS_VALID) + meson_ir_hw_handler(ir); + } spin_unlock(&ir->lock); return IRQ_HANDLED; } +static int meson_ir_hw_decoder_init(struct rc_dev *dev, u64 *rc_type) +{ + u8 protocol; + u32 regval; + int i; + unsigned long flags; + const struct meson_ir_protocol *timings; + struct meson_ir *ir = dev->priv; + + if (*rc_type & RC_PROTO_BIT_NEC) + protocol = DEC_MODE_NEC; + else + return 0; + + for (i = 0; i < ARRAY_SIZE(protocol_timings); i++) + if (protocol_timings[i].hw_protocol == protocol) + break; + + if (i == ARRAY_SIZE(protocol_timings)) { + dev_err(&dev->dev, "hw protocol isn't supported: %d\n", + protocol); + return -EINVAL; + } + timings = &protocol_timings[i]; + + spin_lock_irqsave(&ir->lock, flags); + + /* Clear controller status */ + regmap_read(ir->reg, IR_DEC_STATUS, ®val); + regmap_read(ir->reg, IR_DEC_FRAME, ®val); + + /* Reset ir decoder and disable decoder */ + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_ENABLE, 0); + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_RESET, + IR_DEC_REG1_RESET); + + /* Base time resolution, (19+1)*1us=20us */ + regval = FIELD_PREP(IR_DEC_REG0_BASE_TIME, MESON_HW_TRATE - 1); + regmap_update_bits(ir->reg, IR_DEC_REG0, IR_DEC_REG0_BASE_TIME, regval); + + /* Monitor timing for input filter */ + regmap_update_bits(ir->reg, IR_DEC_REG0, IR_DEC_REG0_FILTER, + FIELD_PREP(IR_DEC_REG0_FILTER, 7)); + + /* HW protocol */ + regval = FIELD_PREP(IR_DEC_REG2_MODE, timings->hw_protocol); + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_MODE, regval); + + /* Hold frame data until register was read */ + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_HOLD_CODE, + timings->hold_code_enable ? + IR_DEC_REG1_HOLD_CODE : 0); + + /* Bit order */ + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_BIT_ORDER, + timings->bit_order ? IR_DEC_REG2_BIT_ORDER : 0); + + /* Select tick mode */ + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_TICK_MODE, + timings->count_tick_mode ? + IR_DEC_REG2_TICK_MODE : 0); + + /* + * Some protocols transmit the same data frame as repeat frame + * when the key is pressing. In this case, it could be detected as + * repeat frame if the repeat checker was enabled. + */ + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_REPEAT_COUNTER, + timings->repeat_counter_enable ? + IR_DEC_REG2_REPEAT_COUNTER : 0); + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_REPEAT_TIME, + timings->repeat_check_enable ? + IR_DEC_REG2_REPEAT_TIME : 0); + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_COMPARE_FRAME, + timings->repeat_compare_enable ? + IR_DEC_REG2_COMPARE_FRAME : 0); + + /* + * FRAME_TIME_MAX should be larger than the time between + * data frame and repeat frame + */ + regval = FIELD_PREP(IR_DEC_REG0_FRAME_TIME_MAX, + timings->frame_time_max); + regmap_update_bits(ir->reg, IR_DEC_REG0, IR_DEC_REG0_FRAME_TIME_MAX, + regval); + + /* Length(N-1) of data frame */ + regval = FIELD_PREP(IR_DEC_REG1_FRAME_LEN, timings->code_length - 1); + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_FRAME_LEN, regval); + + /* Time for leader active part */ + regval = FIELD_PREP(IR_DEC_LDR_ACTIVE_MAX, + timings->leader_active_max) | + FIELD_PREP(IR_DEC_LDR_ACTIVE_MIN, + timings->leader_active_min); + regmap_update_bits(ir->reg, IR_DEC_LDR_ACTIVE, IR_DEC_LDR_ACTIVE_MAX | + IR_DEC_LDR_ACTIVE_MIN, regval); + + /* Time for leader idle part */ + regval = FIELD_PREP(IR_DEC_LDR_IDLE_MAX, timings->leader_idle_max) | + FIELD_PREP(IR_DEC_LDR_IDLE_MIN, timings->leader_idle_min); + regmap_update_bits(ir->reg, IR_DEC_LDR_IDLE, + IR_DEC_LDR_IDLE_MAX | IR_DEC_LDR_IDLE_MIN, regval); + + /* Time for repeat leader idle part */ + regval = FIELD_PREP(IR_DEC_LDR_REPEAT_MAX, timings->repeat_leader_max) | + FIELD_PREP(IR_DEC_LDR_REPEAT_MIN, timings->repeat_leader_min); + regmap_update_bits(ir->reg, IR_DEC_LDR_REPEAT, IR_DEC_LDR_REPEAT_MAX | + IR_DEC_LDR_REPEAT_MIN, regval); + + /* + * NEC: Time for logic '0' + * RC6: Time for half of trailer bit + */ + regval = FIELD_PREP(IR_DEC_BIT_0_MAX, timings->bit0_max) | + FIELD_PREP(IR_DEC_BIT_0_MIN, timings->bit0_min); + regmap_update_bits(ir->reg, IR_DEC_BIT_0, + IR_DEC_BIT_0_MAX | IR_DEC_BIT_0_MIN, regval); + + /* + * NEC: Time for logic '1' + * RC6: Time for whole of trailer bit + */ + regval = FIELD_PREP(IR_DEC_STATUS_BIT_1_MAX, timings->bit1_max) | + FIELD_PREP(IR_DEC_STATUS_BIT_1_MIN, timings->bit1_min); + regmap_update_bits(ir->reg, IR_DEC_STATUS, IR_DEC_STATUS_BIT_1_MAX | + IR_DEC_STATUS_BIT_1_MIN, regval); + + /* Enable to match logic '1' */ + regmap_update_bits(ir->reg, IR_DEC_STATUS, IR_DEC_STATUS_BIT_1_ENABLE, + timings->bit1_match_enable ? + IR_DEC_STATUS_BIT_1_ENABLE : 0); + + /* + * NEC: Unused + * RC6: Time for halt of logic 0/1 + */ + regval = FIELD_PREP(IR_DEC_DURATN2_MAX, timings->duration2_max) | + FIELD_PREP(IR_DEC_DURATN2_MIN, timings->duration2_min); + regmap_update_bits(ir->reg, IR_DEC_DURATN2, + IR_DEC_DURATN2_MAX | IR_DEC_DURATN2_MIN, regval); + + /* + * NEC: Unused + * RC6: Time for whole logic 0/1 + */ + regval = FIELD_PREP(IR_DEC_DURATN3_MAX, timings->duration3_max) | + FIELD_PREP(IR_DEC_DURATN3_MIN, timings->duration3_min); + regmap_update_bits(ir->reg, IR_DEC_DURATN3, + IR_DEC_DURATN3_MAX | IR_DEC_DURATN3_MIN, regval); + + /* Reset ir decoder and enable decode */ + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_RESET, + IR_DEC_REG1_RESET); + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_RESET, 0); + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_ENABLE, + IR_DEC_REG1_ENABLE); + + spin_unlock_irqrestore(&ir->lock, flags); + + dev_info(&dev->dev, "hw decoder init, protocol: %d\n", protocol); + + return 0; +} + +static void meson_ir_sw_decoder_init(struct rc_dev *dev) +{ + unsigned long flags; + struct meson_ir *ir = dev->priv; + + spin_lock_irqsave(&ir->lock, flags); + + /* Reset the decoder */ + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_RESET, + IR_DEC_REG1_RESET); + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_RESET, 0); + + /* Set general operation mode (= raw/software decoding) */ + if (of_device_is_compatible(dev->dev.of_node, "amlogic,meson6-ir")) + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_MODE, + FIELD_PREP(IR_DEC_REG1_MODE, + DEC_MODE_RAW)); + else + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_MODE, + FIELD_PREP(IR_DEC_REG2_MODE, + DEC_MODE_RAW)); + + /* Set rate */ + regmap_update_bits(ir->reg, IR_DEC_REG0, IR_DEC_REG0_BASE_TIME, + FIELD_PREP(IR_DEC_REG0_BASE_TIME, + MESON_RAW_TRATE - 1)); + /* IRQ on rising and falling edges */ + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_IRQSEL, + FIELD_PREP(IR_DEC_REG1_IRQSEL, IRQSEL_RISE_FALL)); + /* Enable the decoder */ + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_ENABLE, + IR_DEC_REG1_ENABLE); + + spin_unlock_irqrestore(&ir->lock, flags); + + dev_info(&dev->dev, "sw decoder init\n"); +} + static int meson_ir_probe(struct platform_device *pdev) { + const struct meson_ir_param *match_data; struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; void __iomem *res_start; @@ -97,10 +455,17 @@ static int meson_ir_probe(struct platform_device *pdev) if (!ir) return -ENOMEM; + match_data = of_device_get_match_data(dev); + if (!match_data) + return dev_err_probe(dev, -ENODEV, "failed to get match data\n"); + + ir->param = match_data; + res_start = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(res_start)) return PTR_ERR(res_start); + meson_ir_regmap_config.max_register = ir->param->max_register; ir->reg = devm_regmap_init_mmio(&pdev->dev, res_start, &meson_ir_regmap_config); if (IS_ERR(ir->reg)) @@ -110,23 +475,34 @@ static int meson_ir_probe(struct platform_device *pdev) if (irq < 0) return irq; - ir->rc = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW); + if (ir->param->support_hw_decoder) + ir->rc = devm_rc_allocate_device(&pdev->dev, + RC_DRIVER_SCANCODE); + else + ir->rc = devm_rc_allocate_device(&pdev->dev, RC_DRIVER_IR_RAW); + if (!ir->rc) { dev_err(dev, "failed to allocate rc device\n"); return -ENOMEM; } + if (ir->rc->driver_type == RC_DRIVER_IR_RAW) { + ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; + ir->rc->rx_resolution = MESON_RAW_TRATE; + ir->rc->min_timeout = 1; + ir->rc->timeout = IR_DEFAULT_TIMEOUT; + ir->rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT; + } else if (ir->rc->driver_type == RC_DRIVER_SCANCODE) { + ir->rc->allowed_protocols = RC_PROTO_BIT_NEC; + ir->rc->change_protocol = meson_ir_hw_decoder_init; + } + ir->rc->priv = ir; ir->rc->device_name = DRIVER_NAME; ir->rc->input_phys = DRIVER_NAME "/input0"; ir->rc->input_id.bustype = BUS_HOST; map_name = of_get_property(node, "linux,rc-map-name", NULL); ir->rc->map_name = map_name ? map_name : RC_MAP_EMPTY; - ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; - ir->rc->rx_resolution = MESON_RAW_TRATE; - ir->rc->min_timeout = 1; - ir->rc->timeout = IR_DEFAULT_TIMEOUT; - ir->rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT; ir->rc->driver_name = DRIVER_NAME; spin_lock_init(&ir->lock); @@ -138,36 +514,15 @@ static int meson_ir_probe(struct platform_device *pdev) return ret; } - ret = devm_request_irq(dev, irq, meson_ir_irq, 0, NULL, ir); + if (ir->rc->driver_type == RC_DRIVER_IR_RAW) + meson_ir_sw_decoder_init(ir->rc); + + ret = devm_request_irq(dev, irq, meson_ir_irq, 0, "meson_ir", ir); if (ret) { dev_err(dev, "failed to request irq\n"); return ret; } - /* Reset the decoder */ - regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_RESET, - IR_DEC_REG1_RESET); - regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_RESET, 0); - - /* Set general operation mode (= raw/software decoding) */ - if (of_device_is_compatible(node, "amlogic,meson6-ir")) - regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_MODE, - FIELD_PREP(IR_DEC_REG1_MODE, DEC_MODE_RAW)); - else - regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_MODE, - FIELD_PREP(IR_DEC_REG2_MODE, DEC_MODE_RAW)); - - /* Set rate */ - regmap_update_bits(ir->reg, IR_DEC_REG0, IR_DEC_REG0_BASE_TIME, - FIELD_PREP(IR_DEC_REG0_BASE_TIME, - MESON_RAW_TRATE - 1)); - /* IRQ on rising and falling edges */ - regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_IRQSEL, - FIELD_PREP(IR_DEC_REG1_IRQSEL, IRQSEL_RISE_FALL)); - /* Enable the decoder */ - regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_ENABLE, - IR_DEC_REG1_ENABLE); - dev_info(dev, "receiver initialized\n"); return 0; @@ -212,11 +567,36 @@ static void meson_ir_shutdown(struct platform_device *pdev) spin_unlock_irqrestore(&ir->lock, flags); } +static const struct meson_ir_param meson6_ir_param = { + .support_hw_decoder = false, + .max_register = IR_DEC_REG1, +}; + +static const struct meson_ir_param meson8b_ir_param = { + .support_hw_decoder = false, + .max_register = IR_DEC_REG2, +}; + +static const struct meson_ir_param meson_s4_ir_param = { + .support_hw_decoder = true, + .max_register = IR_DEC_FRAME1, +}; + static const struct of_device_id meson_ir_match[] = { - { .compatible = "amlogic,meson6-ir" }, - { .compatible = "amlogic,meson8b-ir" }, - { .compatible = "amlogic,meson-gxbb-ir" }, - { }, + { + .compatible = "amlogic,meson6-ir", + .data = &meson6_ir_param, + }, { + .compatible = "amlogic,meson8b-ir", + .data = &meson8b_ir_param, + }, { + .compatible = "amlogic,meson-gxbb-ir", + .data = &meson8b_ir_param, + }, { + .compatible = "amlogic,meson-s4-ir", + .data = &meson_s4_ir_param, + }, + {}, }; MODULE_DEVICE_TABLE(of, meson_ir_match); -- GitLab From 5e05f204a19bb62142e97e30345eb21f2880f392 Mon Sep 17 00:00:00 2001 From: Zelong Dong Date: Fri, 25 Aug 2023 19:53:09 +0800 Subject: [PATCH 0323/1451] dt-bindings: media: Add compatible for Meson-S4 IR Controller Add new compatible for Amlogic's Meson-S4 IR Controller. Meson IR Controller supports hardware decoder in Meson-S4 and later SoC. Signed-off-by: Zelong Dong Acked-by: Krzysztof Kozlowski Signed-off-by: Sean Young Signed-off-by: Hans Verkuil --- Documentation/devicetree/bindings/media/amlogic,meson6-ir.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/media/amlogic,meson6-ir.yaml b/Documentation/devicetree/bindings/media/amlogic,meson6-ir.yaml index 3f9fa92703bbb..0f95fe8dd9ac7 100644 --- a/Documentation/devicetree/bindings/media/amlogic,meson6-ir.yaml +++ b/Documentation/devicetree/bindings/media/amlogic,meson6-ir.yaml @@ -19,6 +19,7 @@ properties: - amlogic,meson6-ir - amlogic,meson8b-ir - amlogic,meson-gxbb-ir + - amlogic,meson-s4-ir - items: - const: amlogic,meson-gx-ir - const: amlogic,meson-gxbb-ir -- GitLab From b55ce3e6b227119040efb838de19b9ded8c84533 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Mon, 19 Jun 2023 07:24:51 +0200 Subject: [PATCH 0324/1451] media: atomisp: ia_css_debug: Removed unused codes for debug This portion of the codes was not referenced so it can be completely removed. Link: https://lore.kernel.org/r/20230619052453.48598-2-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../runtime/debug/interface/ia_css_debug.h | 6 -- .../pci/runtime/debug/src/ia_css_debug.c | 73 ------------------- 2 files changed, 79 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h index fff89e9b4b010..3a3d72c6eaaac 100644 --- a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h +++ b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h @@ -141,12 +141,6 @@ static inline void __printf(2, 0) ia_css_debug_vdtrace(unsigned int level, __printf(2, 3) void ia_css_debug_dtrace(unsigned int level, const char *fmt, ...); -/*! @brief Dump sp thread's stack contents - * SP thread's stack contents are set to 0xcafecafe. This function dumps the - * stack to inspect if the stack's boundaries are compromised. - * @return None - */ -void ia_css_debug_dump_sp_stack_info(void); /*! @brief Function to set the global dtrace verbosity level. * @param[in] trace_level Maximum level of the messages to be traced. diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c index bb6204cb42c5a..3af855d844e5a 100644 --- a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c +++ b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c @@ -147,79 +147,6 @@ void ia_css_debug_dtrace(unsigned int level, const char *fmt, ...) va_end(ap); } -static void debug_dump_long_array_formatted( - const sp_ID_t sp_id, - hrt_address stack_sp_addr, - unsigned int stack_size) -{ - unsigned int i; - u32 val; - u32 addr = (uint32_t)stack_sp_addr; - u32 stack_size_words = CEIL_DIV(stack_size, sizeof(uint32_t)); - - /* When size is not multiple of four, last word is only relevant for - * remaining bytes */ - for (i = 0; i < stack_size_words; i++) { - val = sp_dmem_load_uint32(sp_id, (hrt_address)addr); - if ((i % 8) == 0) - ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "\n"); - - ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "0x%08x ", val); - addr += sizeof(uint32_t); - } - - ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "\n"); -} - -static void debug_dump_sp_stack_info( - const sp_ID_t sp_id) -{ - const struct ia_css_fw_info *fw; - unsigned int HIVE_ADDR_sp_threads_stack; - unsigned int HIVE_ADDR_sp_threads_stack_size; - u32 stack_sizes[MAX_THREAD_NUM]; - u32 stack_sp_addr[MAX_THREAD_NUM]; - unsigned int i; - - fw = &sh_css_sp_fw; - - ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "sp_id(%u) stack info\n", sp_id); - ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, - "from objects stack_addr_offset:0x%x stack_size_offset:0x%x\n", - fw->info.sp.threads_stack, - fw->info.sp.threads_stack_size); - - HIVE_ADDR_sp_threads_stack = fw->info.sp.threads_stack; - HIVE_ADDR_sp_threads_stack_size = fw->info.sp.threads_stack_size; - - if (fw->info.sp.threads_stack == 0 || - fw->info.sp.threads_stack_size == 0) - return; - - (void)HIVE_ADDR_sp_threads_stack; - (void)HIVE_ADDR_sp_threads_stack_size; - - sp_dmem_load(sp_id, - (unsigned int)sp_address_of(sp_threads_stack), - &stack_sp_addr, sizeof(stack_sp_addr)); - sp_dmem_load(sp_id, - (unsigned int)sp_address_of(sp_threads_stack_size), - &stack_sizes, sizeof(stack_sizes)); - - for (i = 0 ; i < MAX_THREAD_NUM; i++) { - ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, - "thread: %u stack_addr: 0x%08x stack_size: %u\n", - i, stack_sp_addr[i], stack_sizes[i]); - debug_dump_long_array_formatted(sp_id, (hrt_address)stack_sp_addr[i], - stack_sizes[i]); - } -} - -void ia_css_debug_dump_sp_stack_info(void) -{ - debug_dump_sp_stack_info(SP0_ID); -} - void ia_css_debug_set_dtrace_level(const unsigned int trace_level) { dbg_level = trace_level; -- GitLab From 55c3407c63fbdfef0a5632ac6d09e2e76334fef2 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Mon, 19 Jun 2023 07:24:52 +0200 Subject: [PATCH 0325/1451] media: atomisp: Removed unused HAS_WATCHDOG_SP_THREAD_DEBUG debug Since the debug codes around #ifdef HAS_WATCHDOG_SP_THREAD_DEBUG are no longer used, the debug implementation of this can be removed. Link: https://lore.kernel.org/r/20230619052453.48598-3-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../pci/hive_isp_css_common/debug_global.h | 7 -- .../media/atomisp/pci/ia_css_acc_types.h | 6 +- .../runtime/debug/interface/ia_css_debug.h | 6 -- .../pci/runtime/debug/src/ia_css_debug.c | 92 ------------------- .../media/atomisp/pci/sh_css_internal.h | 23 ----- 5 files changed, 1 insertion(+), 133 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/debug_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/debug_global.h index b6538beca18ad..f2e17945fd453 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/debug_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/debug_global.h @@ -35,13 +35,6 @@ #define DEBUG_BUFFER_ISP_DMEM_ADDR 0x0 -/* - * Enable HAS_WATCHDOG_SP_THREAD_DEBUG for additional SP thread and - * pipe information on watchdog output - * #undef HAS_WATCHDOG_SP_THREAD_DEBUG - * #define HAS_WATCHDOG_SP_THREAD_DEBUG - */ - /* * The linear buffer mode will accept data until the first * overflow and then stop accepting new data diff --git a/drivers/staging/media/atomisp/pci/ia_css_acc_types.h b/drivers/staging/media/atomisp/pci/ia_css_acc_types.h index a20879aedef67..d6e52b4971d68 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_acc_types.h +++ b/drivers/staging/media/atomisp/pci/ia_css_acc_types.h @@ -331,11 +331,7 @@ struct ia_css_sp_info { of DDR debug queue */ u32 perf_counter_input_system_error; /** input system perf counter array */ -#ifdef HAS_WATCHDOG_SP_THREAD_DEBUG - u32 debug_wait; /** thread/pipe post mortem debug */ - u32 debug_stage; /** thread/pipe post mortem debug */ - u32 debug_stripe; /** thread/pipe post mortem debug */ -#endif + u32 threads_stack; /** sp thread's stack pointers */ u32 threads_stack_size; /** sp thread's stack sizes */ u32 curr_binary_id; /** current binary id */ diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h index 3a3d72c6eaaac..efa1362948364 100644 --- a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h +++ b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h @@ -306,12 +306,6 @@ void ia_css_debug_dump_isp_params(struct ia_css_stream *stream, */ void ia_css_debug_dump_perf_counters(void); -#ifdef HAS_WATCHDOG_SP_THREAD_DEBUG -void sh_css_dump_thread_wait_info(void); -void sh_css_dump_pipe_stage_info(void); -void sh_css_dump_pipe_stripe_info(void); -#endif - void ia_css_debug_dump_isp_binary(void); void sh_css_dump_sp_raw_copy_linecount(bool reduced); diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c index 3af855d844e5a..cf66a40bd6a44 100644 --- a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c +++ b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c @@ -101,12 +101,6 @@ #define ENABLE_LINE_MAX_LENGTH (25) -/* - * TODO:SH_CSS_MAX_SP_THREADS is not the max number of sp threads - * future rework should fix this and remove the define MAX_THREAD_NUM - */ -#define MAX_THREAD_NUM (SH_CSS_MAX_SP_THREADS + SH_CSS_MAX_SP_INTERNAL_THREADS) - static struct pipe_graph_class { bool do_init; int height; @@ -2074,12 +2068,6 @@ void ia_css_debug_dump_debug_info(const char *context) ia_css_debug_dump_isp_gdc_fifo_state(); ia_css_debug_dump_sp_state(); ia_css_debug_dump_perf_counters(); - -#ifdef HAS_WATCHDOG_SP_THREAD_DEBUG - sh_css_dump_thread_wait_info(); - sh_css_dump_pipe_stage_info(); - sh_css_dump_pipe_stripe_info(); -#endif ia_css_debug_dump_dma_isp_fifo_state(); ia_css_debug_dump_dma_sp_fifo_state(); ia_css_debug_dump_dma_state(); @@ -2391,86 +2379,6 @@ static void __printf(1, 2) dtrace_dot(const char *fmt, ...) va_end(ap); } -#ifdef HAS_WATCHDOG_SP_THREAD_DEBUG -void sh_css_dump_thread_wait_info(void) -{ - const struct ia_css_fw_info *fw; - int i; - unsigned int HIVE_ADDR_sp_thread_wait; - s32 sp_thread_wait[MAX_THREAD_NUM]; - - ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "SEM WAITS:\n"); - - fw = &sh_css_sp_fw; - HIVE_ADDR_sp_thread_wait = - fw->info.sp.debug_wait; - - (void)HIVE_ADDR_sp_thread_wait; - - sp_dmem_load(SP0_ID, - (unsigned int)sp_address_of(sp_thread_wait), - &sp_thread_wait, - sizeof(sp_thread_wait)); - for (i = 0; i < MAX_THREAD_NUM; i++) { - ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, - "\twait[%d] = 0x%X\n", - i, sp_thread_wait[i]); - } -} - -void sh_css_dump_pipe_stage_info(void) -{ - const struct ia_css_fw_info *fw; - int i; - unsigned int HIVE_ADDR_sp_pipe_stage; - s32 sp_pipe_stage[MAX_THREAD_NUM]; - - ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "PIPE STAGE:\n"); - - fw = &sh_css_sp_fw; - HIVE_ADDR_sp_pipe_stage = - fw->info.sp.debug_stage; - - (void)HIVE_ADDR_sp_pipe_stage; - - sp_dmem_load(SP0_ID, - (unsigned int)sp_address_of(sp_pipe_stage), - &sp_pipe_stage, - sizeof(sp_pipe_stage)); - for (i = 0; i < MAX_THREAD_NUM; i++) { - ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, - "\tstage[%d] = %d\n", - i, sp_pipe_stage[i]); - } -} - -void sh_css_dump_pipe_stripe_info(void) -{ - const struct ia_css_fw_info *fw; - int i; - unsigned int HIVE_ADDR_sp_pipe_stripe; - s32 sp_pipe_stripe[MAX_THREAD_NUM]; - - ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "PIPE STRIPE:\n"); - - fw = &sh_css_sp_fw; - HIVE_ADDR_sp_pipe_stripe = - fw->info.sp.debug_stripe; - - (void)HIVE_ADDR_sp_pipe_stripe; - - sp_dmem_load(SP0_ID, - (unsigned int)sp_address_of(sp_pipe_stripe), - &sp_pipe_stripe, - sizeof(sp_pipe_stripe)); - for (i = 0; i < MAX_THREAD_NUM; i++) { - ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, - "\tstripe[%d] = %d\n", - i, sp_pipe_stripe[i]); - } -} -#endif - static void ia_css_debug_pipe_graph_dump_frame( const struct ia_css_frame *frame, diff --git a/drivers/staging/media/atomisp/pci/sh_css_internal.h b/drivers/staging/media/atomisp/pci/sh_css_internal.h index d98f1323441ea..ef7d43de4a6ad 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_internal.h +++ b/drivers/staging/media/atomisp/pci/sh_css_internal.h @@ -86,31 +86,8 @@ #define SH_CSS_MAX_IF_CONFIGS 3 /* Must match with IA_CSS_NR_OF_CONFIGS (not defined yet).*/ #define SH_CSS_IF_CONFIG_NOT_NEEDED 0xFF -/* - * SH_CSS_MAX_SP_THREADS: - * sp threads visible to host with connected communication queues - * these threads are capable of running an image pipe - * SH_CSS_MAX_SP_INTERNAL_THREADS: - * internal sp service threads, no communication queues to host - * these threads can't be used as image pipe - */ - -#if !defined(ISP2401) -#define SH_CSS_SP_INTERNAL_METADATA_THREAD 1 -#else -#define SH_CSS_SP_INTERNAL_METADATA_THREAD 0 -#endif - -#define SH_CSS_SP_INTERNAL_SERVICE_THREAD 1 - #define SH_CSS_MAX_SP_THREADS 5 -#define SH_CSS_MAX_SP_INTERNAL_THREADS (\ - SH_CSS_SP_INTERNAL_SERVICE_THREAD +\ - SH_CSS_SP_INTERNAL_METADATA_THREAD) - -#define SH_CSS_MAX_PIPELINES SH_CSS_MAX_SP_THREADS - /** * The C99 standard does not specify the exact object representation of structs; * the representation is compiler dependent. -- GitLab From 921f9a1945e4f0109552d5526013a5b88ea7ce5f Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Mon, 19 Jun 2023 07:24:53 +0200 Subject: [PATCH 0326/1451] media: atomisp: sh_css_internal: sh_css_params: Unifying sh_css_sp_group data structure Since some parts of the data structure elements are determined in compile time, the configuration data structure should be compiled for both two ISP models. In order to set the configuration for both ISP models in runtime, The sh_css_sp_group is unified to one data structure for the configuration to ensure the data structure can be used for both ISP2400 and 2401 in runtime. Also, the unused codes for debug purpose are removed. Form the aspect of ISP setting, the length and the content of the configuration structure for ISP2400 and ISP2401 are different. So, we need to pick up the necessary part of sp_group configuration for both models and then copy those parts into a temporary buffer. This buffer is finally written to the ISP with the corresponding length. Link: https://lore.kernel.org/r/20230619052453.48598-4-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/pci/sh_css_internal.h | 18 +------- .../staging/media/atomisp/pci/sh_css_params.c | 41 ++++++++++++++++++- 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css_internal.h b/drivers/staging/media/atomisp/pci/sh_css_internal.h index ef7d43de4a6ad..2349eb4d3767e 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_internal.h +++ b/drivers/staging/media/atomisp/pci/sh_css_internal.h @@ -22,9 +22,7 @@ #include #include -#if !defined(ISP2401) #include "input_formatter.h" -#endif #include "input_system.h" #include "ia_css_types.h" @@ -334,14 +332,12 @@ struct sh_css_sp_debug_command { u32 dma_sw_reg; }; -#if !defined(ISP2401) /* SP input formatter configuration.*/ struct sh_css_sp_input_formatter_set { u32 stream_format; input_formatter_cfg_t config_a; input_formatter_cfg_t config_b; }; -#endif #define IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT (3) @@ -354,7 +350,7 @@ struct sh_css_sp_config { frames are locked when their EOF event is successfully sent to the host (true) or when they are passed to the preview/video pipe (false). */ -#if !defined(ISP2401) + struct { u8 a_changed; u8 b_changed; @@ -362,15 +358,13 @@ struct sh_css_sp_config { struct sh_css_sp_input_formatter_set set[SH_CSS_MAX_IF_CONFIGS]; /* CSI-2 port is used as index. */ } input_formatter; -#endif -#if !defined(ISP2401) + sync_generator_cfg_t sync_gen; tpg_cfg_t tpg; prbs_cfg_t prbs; input_system_cfg_t input_circuit; u8 input_circuit_cfg_changed; u32 mipi_sizes_for_check[N_CSI_PORTS][IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT]; -#endif u8 enable_isys_event_queue; u8 disable_cont_vf; }; @@ -386,7 +380,6 @@ enum sh_css_stage_type { #define SH_CSS_PIPE_CONFIG_SAMPLE_PARAMS_MASK \ ((SH_CSS_PIPE_CONFIG_SAMPLE_PARAMS << SH_CSS_MAX_SP_THREADS) - 1) -#if defined(ISP2401) struct sh_css_sp_pipeline_terminal { union { /* Input System 2401 */ @@ -419,7 +412,6 @@ struct sh_css_sp_pipeline_io_status { u32 running[N_INPUT_SYSTEM_CSI_PORT]; /** configured streams */ }; -#endif enum sh_css_port_dir { SH_CSS_PORT_INPUT = 0, SH_CSS_PORT_OUTPUT = 1 @@ -618,10 +610,8 @@ struct sh_css_sp_stage { struct sh_css_sp_group { struct sh_css_sp_config config; struct sh_css_sp_pipeline pipe[SH_CSS_MAX_SP_THREADS]; -#if defined(ISP2401) struct sh_css_sp_pipeline_io pipe_io[SH_CSS_MAX_SP_THREADS]; struct sh_css_sp_pipeline_io_status pipe_io_status; -#endif struct sh_css_sp_debug_command debug; }; @@ -899,13 +889,11 @@ sh_css_frame_info_set_width(struct ia_css_frame_info *info, unsigned int width, unsigned int aligned); -#if !defined(ISP2401) unsigned int sh_css_get_mipi_sizes_for_check(const unsigned int port, const unsigned int idx); -#endif ia_css_ptr sh_css_store_sp_group_to_ddr(void); @@ -948,11 +936,9 @@ sh_css_continuous_is_enabled(uint8_t pipe_num); struct ia_css_pipe * find_pipe_by_num(uint32_t pipe_num); -#ifdef ISP2401 void ia_css_get_crop_offsets( struct ia_css_pipe *pipe, struct ia_css_frame_info *in_frame); -#endif #endif /* _SH_CSS_INTERNAL_H_ */ diff --git a/drivers/staging/media/atomisp/pci/sh_css_params.c b/drivers/staging/media/atomisp/pci/sh_css_params.c index 588f2adab058c..5667e855da766 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_params.c +++ b/drivers/staging/media/atomisp/pci/sh_css_params.c @@ -3720,10 +3720,47 @@ struct ia_css_shading_table *ia_css_get_shading_table(struct ia_css_stream ia_css_ptr sh_css_store_sp_group_to_ddr(void) { + u8 *write_buf; + u8 *buf_ptr; + IA_CSS_ENTER_LEAVE_PRIVATE("void"); + + write_buf = kzalloc(sizeof(u8) * 8192, GFP_KERNEL); + if (!write_buf) + return 0; + + buf_ptr = write_buf; + if (IS_ISP2401) { + memcpy(buf_ptr, &sh_css_sp_group.config, 3); + buf_ptr += 3; + memcpy(buf_ptr, &sh_css_sp_group.config.enable_isys_event_queue, 2); + buf_ptr += 2; + memset(buf_ptr, 0, 3); + buf_ptr += 3; /* Padding 3 bytes for struct sh_css_sp_config*/ + } else { + memcpy(buf_ptr, &sh_css_sp_group.config, sizeof(sh_css_sp_group.config)); + buf_ptr += sizeof(sh_css_sp_group.config); + } + + memcpy(buf_ptr, &sh_css_sp_group.pipe, sizeof(sh_css_sp_group.pipe)); + buf_ptr += sizeof(sh_css_sp_group.pipe); + + if (IS_ISP2401) { + memcpy(buf_ptr, &sh_css_sp_group.pipe_io, sizeof(sh_css_sp_group.pipe_io)); + buf_ptr += sizeof(sh_css_sp_group.pipe_io); + memcpy(buf_ptr, &sh_css_sp_group.pipe_io_status, + sizeof(sh_css_sp_group.pipe_io_status)); + buf_ptr += sizeof(sh_css_sp_group.pipe_io_status); + } + + memcpy(buf_ptr, &sh_css_sp_group.debug, sizeof(sh_css_sp_group.debug)); + buf_ptr += sizeof(sh_css_sp_group.debug); + hmm_store(xmem_sp_group_ptrs, - &sh_css_sp_group, - sizeof(struct sh_css_sp_group)); + write_buf, + buf_ptr - write_buf); + + kfree(write_buf); return xmem_sp_group_ptrs; } -- GitLab From 0e2c53ff13e2240dea196d5813cc08ea923951dc Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 19 Jun 2023 12:52:06 +0200 Subject: [PATCH 0327/1451] media: atomisp: Fix missing v4l2_fh_release() in atomisp_open() error exit Fix missing v4l2_fh_release() in atomisp_open()'s "if (pipe->users)" error exit path. Closes: https://lore.kernel.org/r/202306180511.XWN0Hr7F-lkp@intel.com/ Link: https://lore.kernel.org/r/20230619105212.303653-1-hdegoede@redhat.com Reported-by: kernel test robot Reported-by: Dan Carpenter Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_fops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp_fops.c index 54466d2f323a1..a09087dccbcb7 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.c @@ -513,8 +513,8 @@ static int atomisp_open(struct file *file) */ if (pipe->users) { dev_dbg(isp->dev, "video node already opened\n"); - mutex_unlock(&isp->mutex); - return -EBUSY; + ret = -EBUSY; + goto error; } /* runtime power management, turn on ISP */ -- GitLab From d86c33af672d126bbba0b61947078c317994dcc5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 19 Jun 2023 12:52:08 +0200 Subject: [PATCH 0328/1451] media: atomisp: Clamp width to max 1920 pixels when in ATOMISP_RUN_MODE_PREVIEW The pipeline firmware-binaries used in previed mode have ia_css_binary_xinfo.output.max_width set to 1920. This causes ia_css_binary_find() to fail when trying to set a higher resolution resulting in the dump_stack() call in ia_css_binary_find() triggering and resulting in the try_fmt() or set_fmt() IOCTL failing. Fix this by clamping the width to max 1920 when in preview mode. Link: https://lore.kernel.org/r/20230619105212.303653-3-hdegoede@redhat.com Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_cmd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c index 0803b296e9acc..a5110636d6f54 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c @@ -3808,6 +3808,10 @@ int atomisp_try_fmt(struct atomisp_device *isp, struct v4l2_pix_format *f, return -EINVAL; } + /* The preview pipeline does not support width > 1920 */ + if (asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW) + f->width = min_t(u32, f->width, 1920); + /* * atomisp_set_fmt() will set the sensor resolution to the requested * resolution + padding. Add padding here and remove it again after -- GitLab From b24209cf1c5c47bee31d0f03dae6f2349b8b85ac Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 19 Jun 2023 12:52:09 +0200 Subject: [PATCH 0329/1451] media: atomisp: Change atomisp_enum_framesizes() too small cut off from 2/3th to 5/8th Change atomisp_enum_framesizes() cut off for too small resolutions from 2/3th to 5/8th this results in more resolutions being available with some sensors. E.g. this allows using 800x600 with a 1280x960 sensor. Link: https://lore.kernel.org/r/20230619105212.303653-4-hdegoede@redhat.com Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_ioctl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c index d2174156573a5..047b9fb075d04 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c @@ -729,11 +729,11 @@ static int atomisp_enum_framesizes_crop_inner(struct atomisp_device *isp, continue; /* - * Skip sizes where width and height are less then 2/3th of the + * Skip sizes where width and height are less then 5/8th of the * sensor size to avoid sizes with a too small field of view. */ - if (frame_sizes[i].width < (active->width * 2 / 3) && - frame_sizes[i].height < (active->height * 2 / 3)) + if (frame_sizes[i].width < (active->width * 5 / 8) && + frame_sizes[i].height < (active->height * 5 / 8)) continue; if (*valid_sizes == fsize->index) { -- GitLab From 2ffb2e640c8aae2bef59848c93fcb6bf03152424 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 19 Jun 2023 12:52:10 +0200 Subject: [PATCH 0330/1451] media: atomisp: Add some higher resolutions to atomisp_enum_framesizes() Add some higher resolutions to the fixed list of resolutions which atomisp_enum_framesizes() uses on sensors which can do cropping and can thus make any resolution that will fit. This is useful for higher resolution sensors like the 2560x1920 ov5693 sensor. Note the highest resolutions added here are 1920x because the atomisp firmware does not support widths > 1920 with the default asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW setting. Link: https://lore.kernel.org/r/20230619105212.303653-5-hdegoede@redhat.com Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_ioctl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c index 047b9fb075d04..8fd981f496595 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c @@ -708,6 +708,9 @@ static int atomisp_enum_framesizes_crop_inner(struct atomisp_device *isp, int *valid_sizes) { static const struct v4l2_frmsize_discrete frame_sizes[] = { + { 1920, 1440 }, + { 1920, 1200 }, + { 1920, 1080 }, { 1600, 1200 }, { 1600, 1080 }, { 1600, 900 }, -- GitLab From b6da9e5a061751f92be7f18208a4aab9e52f24da Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 19 Jun 2023 12:52:11 +0200 Subject: [PATCH 0331/1451] media: atomisp: Remove support for custom run-mode v4l2-ctrl on sensors Remove the support to update a V4L2_CID_RUN_MODE run-mode control on sensors when changing the atomisp run-mode or directly by calling the custom ATOMISP_IOC_S_SENSOR_RUNMODE IOCTL. No sensor drivers implement this and having custom controls / IOCTLs is undesirable. Even if there was such a control on sensors then userspace should directly talk to the sensor v4l2-subdev, rather than relying on a custom IOCTLs on the output /dev/video# node to pass this through to the senor. Link: https://lore.kernel.org/r/20230619105212.303653-6-hdegoede@redhat.com Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/include/linux/atomisp.h | 10 ---- .../staging/media/atomisp/pci/atomisp_cmd.c | 22 --------- .../staging/media/atomisp/pci/atomisp_cmd.h | 13 ----- .../staging/media/atomisp/pci/atomisp_ioctl.c | 12 ----- .../media/atomisp/pci/atomisp_subdev.c | 48 ------------------- .../media/atomisp/pci/atomisp_subdev.h | 2 - 6 files changed, 107 deletions(-) diff --git a/drivers/staging/media/atomisp/include/linux/atomisp.h b/drivers/staging/media/atomisp/include/linux/atomisp.h index 14b1757e66746..bbbd904b696a3 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp.h @@ -713,13 +713,6 @@ enum atomisp_burst_capture_options { #define EXT_ISP_SHOT_MODE_ANIMATED_PHOTO 10 #define EXT_ISP_SHOT_MODE_SPORTS 11 -/* - * Set Senor run mode - */ -struct atomisp_s_runmode { - __u32 mode; -}; - /*Private IOCTLs for ISP */ #define ATOMISP_IOC_G_XNR \ _IOR('v', BASE_VIDIOC_PRIVATE + 0, int) @@ -875,9 +868,6 @@ struct atomisp_s_runmode { #define ATOMISP_IOC_S_SENSOR_EE_CONFIG \ _IOW('v', BASE_VIDIOC_PRIVATE + 47, unsigned int) -#define ATOMISP_IOC_S_SENSOR_RUNMODE \ - _IOW('v', BASE_VIDIOC_PRIVATE + 48, struct atomisp_s_runmode) - /* * Reserved ioctls. We have customer implementing it internally. * We can't use both numbers to not cause ABI conflict. diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c index a5110636d6f54..a54be2d20c587 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c @@ -1248,28 +1248,6 @@ static void atomisp_update_capture_mode(struct atomisp_sub_device *asd) atomisp_css_capture_set_mode(asd, IA_CSS_CAPTURE_MODE_PRIMARY); } -/* ISP2401 */ -int atomisp_set_sensor_runmode(struct atomisp_sub_device *asd, - struct atomisp_s_runmode *runmode) -{ - struct atomisp_device *isp = asd->isp; - struct v4l2_ctrl *c; - int ret = 0; - - if (!(runmode && (runmode->mode & RUNMODE_MASK))) - return -EINVAL; - - mutex_lock(asd->ctrl_handler.lock); - c = v4l2_ctrl_find(isp->inputs[asd->input_curr].camera->ctrl_handler, - V4L2_CID_RUN_MODE); - - if (c) - ret = v4l2_ctrl_s_ctrl(c, runmode->mode); - - mutex_unlock(asd->ctrl_handler.lock); - return ret; -} - /* * Function to enable/disable lens geometry distortion correction (GDC) and * chromatic aberration correction (CAC) diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.h b/drivers/staging/media/atomisp/pci/atomisp_cmd.h index 8305161d20628..b8cd957eebdc2 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.h +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.h @@ -42,13 +42,6 @@ struct ia_css_frame; #define INTR_IER 24 #define INTR_IIR 16 -/* ISP2401 */ -#define RUNMODE_MASK (ATOMISP_RUN_MODE_VIDEO | ATOMISP_RUN_MODE_STILL_CAPTURE \ - | ATOMISP_RUN_MODE_PREVIEW) - -/* FIXME: check if can go */ -extern int atomisp_punit_hpll_freq; - /* Helper function */ void dump_sp_dmem(struct atomisp_device *isp, unsigned int addr, unsigned int size); @@ -77,12 +70,6 @@ bool atomisp_is_viewfinder_support(struct atomisp_device *isp); /* ISP features control function */ -/* - * Function to set sensor runmode by user when - * ATOMISP_IOC_S_SENSOR_RUNMODE ioctl was called - */ -int atomisp_set_sensor_runmode(struct atomisp_sub_device *asd, - struct atomisp_s_runmode *runmode); /* * Function to enable/disable lens geometry distortion correction (GDC) and * chromatic aberration correction (CAC) diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c index 8fd981f496595..a8e4779d007f4 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c @@ -665,11 +665,6 @@ static int atomisp_s_input(struct file *file, void *fh, unsigned int input) dev_err(isp->dev, "Failed to power-on sensor\n"); return ret; } - /* - * Some sensor driver resets the run mode during power-on, thus force - * update the run mode to sensor after power-on. - */ - atomisp_update_run_mode(asd); /* select operating sensor */ ret = v4l2_subdev_call(isp->inputs[input].camera, video, s_routing, @@ -1784,13 +1779,6 @@ static long atomisp_vidioc_default(struct file *file, void *fh, int err; switch (cmd) { - case ATOMISP_IOC_S_SENSOR_RUNMODE: - if (IS_ISP2401) - err = atomisp_set_sensor_runmode(asd, arg); - else - err = -EINVAL; - break; - case ATOMISP_IOC_G_XNR: err = atomisp_xnr(asd, 0, arg); break; diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp_subdev.c index 45073e401bac4..471912dea5cd8 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.c +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.c @@ -663,52 +663,6 @@ static const struct media_entity_operations isp_subdev_media_ops = { /* .set_power = v4l2_subdev_set_power, */ }; -static int __atomisp_update_run_mode(struct atomisp_sub_device *asd) -{ - struct atomisp_device *isp = asd->isp; - struct v4l2_ctrl *ctrl = asd->run_mode; - struct v4l2_ctrl *c; - s32 mode; - - mode = ctrl->val; - - c = v4l2_ctrl_find( - isp->inputs[asd->input_curr].camera->ctrl_handler, - V4L2_CID_RUN_MODE); - - if (c) - return v4l2_ctrl_s_ctrl(c, mode); - - return 0; -} - -int atomisp_update_run_mode(struct atomisp_sub_device *asd) -{ - int rval; - - mutex_lock(asd->ctrl_handler.lock); - rval = __atomisp_update_run_mode(asd); - mutex_unlock(asd->ctrl_handler.lock); - - return rval; -} - -static int s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct atomisp_sub_device *asd = container_of( - ctrl->handler, struct atomisp_sub_device, ctrl_handler); - switch (ctrl->id) { - case V4L2_CID_RUN_MODE: - return __atomisp_update_run_mode(asd); - } - - return 0; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .s_ctrl = &s_ctrl, -}; - static const char *const ctrl_run_mode_menu[] = { [ATOMISP_RUN_MODE_VIDEO] = "Video", [ATOMISP_RUN_MODE_STILL_CAPTURE] = "Still capture", @@ -716,7 +670,6 @@ static const char *const ctrl_run_mode_menu[] = { }; static const struct v4l2_ctrl_config ctrl_run_mode = { - .ops = &ctrl_ops, .id = V4L2_CID_RUN_MODE, .name = "Atomisp run mode", .type = V4L2_CTRL_TYPE_MENU, @@ -754,7 +707,6 @@ static const struct v4l2_ctrl_config ctrl_vfpp = { * the CSS subsystem. */ static const struct v4l2_ctrl_config ctrl_continuous_raw_buffer_size = { - .ops = &ctrl_ops, .id = V4L2_CID_ATOMISP_CONTINUOUS_RAW_BUFFER_SIZE, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Continuous raw ringbuffer size", diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.h b/drivers/staging/media/atomisp/pci/atomisp_subdev.h index 9a04511b9efd1..9c1703bf439cf 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.h +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.h @@ -360,8 +360,6 @@ void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd, uint32_t which, u32 pad, struct v4l2_mbus_framefmt *ffmt); -int atomisp_update_run_mode(struct atomisp_sub_device *asd); - void atomisp_subdev_cleanup_pending_events(struct atomisp_sub_device *asd); void atomisp_subdev_unregister_entities(struct atomisp_sub_device *asd); -- GitLab From 10c6c42859cc381e9176594544b15e7260737e56 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 19 Jun 2023 12:52:12 +0200 Subject: [PATCH 0332/1451] media: atomisp: Remove v4l2_ctrl_s_ctrl(asd->run_mode) calls from atomisp_open() The v4l2_ctrl_s_ctrl(asd->run_mode) call in atomisp_subdev_init_struct() gets immediately overridden by a second call directly after atomisp_subdev_init_struct() is called. And the second call in atomisp_open() also is not helpful. ATOMISP_RUN_MODE_PREVIEW is the default and if changed controls are supposed to stay changed over an open/close of the /dev/video# node. So drop both calls. Link: https://lore.kernel.org/r/20230619105212.303653-7-hdegoede@redhat.com Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_fops.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp_fops.c index a09087dccbcb7..4dba6120af391 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.c @@ -460,7 +460,6 @@ static void atomisp_dev_init_struct(struct atomisp_device *isp) static void atomisp_subdev_init_struct(struct atomisp_sub_device *asd) { - v4l2_ctrl_s_ctrl(asd->run_mode, ATOMISP_RUN_MODE_STILL_CAPTURE); memset(&asd->params.css_param, 0, sizeof(asd->params.css_param)); asd->params.color_effect = V4L2_COLORFX_NONE; asd->params.bad_pixel_en = true; @@ -533,8 +532,6 @@ static int atomisp_open(struct file *file) } atomisp_subdev_init_struct(asd); - /* Ensure that a mode is set */ - v4l2_ctrl_s_ctrl(asd->run_mode, ATOMISP_RUN_MODE_PREVIEW); pipe->users++; mutex_unlock(&isp->mutex); -- GitLab From b0e59612eb2cbb5c62343fba60893451bbfb4bbf Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Thu, 13 Jul 2023 12:02:21 +0200 Subject: [PATCH 0333/1451] media: atomisp: ia_css_debug: Removed debug codes for dumping status This portion of debug code was based on a structure for both ISP2400 and 2401 with the same name and controlled by #if defined(ISP2401). This structure was only used to dump the status of atomisp. So, to make the driver generic, this part of debug codes can be removed. Link: https://lore.kernel.org/r/20230713100231.308923-2-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../hive_isp_css_common/host/input_system.c | 60 ---- .../hive_isp_css_include/host/isys_public.h | 19 -- .../atomisp/pci/isp2400_input_system_local.h | 17 -- .../atomisp/pci/isp2400_input_system_public.h | 4 - .../atomisp/pci/isp2401_input_system_local.h | 10 +- .../pci/isp2401_input_system_private.h | 108 -------- .../runtime/debug/interface/ia_css_debug.h | 6 - .../pci/runtime/debug/src/ia_css_debug.c | 256 ------------------ drivers/staging/media/atomisp/pci/sh_css.c | 2 - 9 files changed, 1 insertion(+), 481 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c index 712e01c37870c..09aca4e3db226 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c @@ -116,66 +116,6 @@ static void input_switch_cfg( const input_switch_cfg_t *const cfg ); -void input_system_get_state( - const input_system_ID_t ID, - input_system_state_t *state) -{ - sub_system_ID_t sub_id; - - assert(ID < N_INPUT_SYSTEM_ID); - assert(state); - - state->str_multicastA_sel = input_system_sub_system_reg_load(ID, - GPREGS_UNIT0_ID, - HIVE_ISYS_GPREG_MULTICAST_A_IDX); - state->str_multicastB_sel = input_system_sub_system_reg_load(ID, - GPREGS_UNIT0_ID, - HIVE_ISYS_GPREG_MULTICAST_B_IDX); - state->str_multicastC_sel = input_system_sub_system_reg_load(ID, - GPREGS_UNIT0_ID, - HIVE_ISYS_GPREG_MULTICAST_C_IDX); - state->str_mux_sel = input_system_sub_system_reg_load(ID, - GPREGS_UNIT0_ID, - HIVE_ISYS_GPREG_MUX_IDX); - state->str_mon_status = input_system_sub_system_reg_load(ID, - GPREGS_UNIT0_ID, - HIVE_ISYS_GPREG_STRMON_STAT_IDX); - state->str_mon_irq_cond = input_system_sub_system_reg_load(ID, - GPREGS_UNIT0_ID, - HIVE_ISYS_GPREG_STRMON_COND_IDX); - state->str_mon_irq_en = input_system_sub_system_reg_load(ID, - GPREGS_UNIT0_ID, - HIVE_ISYS_GPREG_STRMON_IRQ_EN_IDX); - state->isys_srst = input_system_sub_system_reg_load(ID, - GPREGS_UNIT0_ID, - HIVE_ISYS_GPREG_SRST_IDX); - state->isys_slv_reg_srst = input_system_sub_system_reg_load(ID, - GPREGS_UNIT0_ID, - HIVE_ISYS_GPREG_SLV_REG_SRST_IDX); - state->str_deint_portA_cnt = input_system_sub_system_reg_load(ID, - GPREGS_UNIT0_ID, - HIVE_ISYS_GPREG_REG_PORT_A_IDX); - state->str_deint_portB_cnt = input_system_sub_system_reg_load(ID, - GPREGS_UNIT0_ID, - HIVE_ISYS_GPREG_REG_PORT_B_IDX); - - for (sub_id = CAPTURE_UNIT0_ID; sub_id < CAPTURE_UNIT0_ID + N_CAPTURE_UNIT_ID; - sub_id++) { - capture_unit_get_state(ID, sub_id, - &state->capture_unit[sub_id - CAPTURE_UNIT0_ID]); - } - for (sub_id = ACQUISITION_UNIT0_ID; - sub_id < ACQUISITION_UNIT0_ID + N_ACQUISITION_UNIT_ID; sub_id++) { - acquisition_unit_get_state(ID, sub_id, - &state->acquisition_unit[sub_id - ACQUISITION_UNIT0_ID]); - } - for (sub_id = CTRL_UNIT0_ID; sub_id < CTRL_UNIT0_ID + N_CTRL_UNIT_ID; - sub_id++) { - ctrl_unit_get_state(ID, sub_id, - &state->ctrl_unit_state[sub_id - CTRL_UNIT0_ID]); - } -} - void receiver_get_state( const rx_ID_t ID, receiver_state_t *state) diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_public.h index dac53e3241184..9dacef7a5cc1f 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_public.h @@ -16,23 +16,4 @@ #ifndef __ISYS_PUBLIC_H_INCLUDED__ #define __ISYS_PUBLIC_H_INCLUDED__ -#ifdef ISP2401 -/*! Read the state of INPUT_SYSTEM[ID] - \param ID[in] INPUT_SYSTEM identifier - \param state[out] pointer to input system state structure - \return none, state = INPUT_SYSTEM[ID].state - */ -STORAGE_CLASS_INPUT_SYSTEM_H input_system_err_t input_system_get_state( - const input_system_ID_t ID, - input_system_state_t *state); -/*! Dump the state of INPUT_SYSTEM[ID] - \param ID[in] INPUT_SYSTEM identifier - \param state[in] pointer to input system state structure - \return none - \depends on host supplied print function as part of ia_css_init() - */ -STORAGE_CLASS_INPUT_SYSTEM_H void input_system_dump_state( - const input_system_ID_t ID, - input_system_state_t *state); -#endif /* ISP2401 */ #endif /* __ISYS_PUBLIC_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h index c3ae5014a0395..8701abc4c9919 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h @@ -306,23 +306,6 @@ struct ctrl_unit_state_s { int capt_reserve_one_mem_region; }; -struct input_system_state_s { - int str_multicastA_sel; - int str_multicastB_sel; - int str_multicastC_sel; - int str_mux_sel; - int str_mon_status; - int str_mon_irq_cond; - int str_mon_irq_en; - int isys_srst; - int isys_slv_reg_srst; - int str_deint_portA_cnt; - int str_deint_portB_cnt; - struct capture_unit_state_s capture_unit[N_CAPTURE_UNIT_ID]; - struct acquisition_unit_state_s acquisition_unit[N_ACQUISITION_UNIT_ID]; - struct ctrl_unit_state_s ctrl_unit_state[N_CTRL_UNIT_ID]; -}; - struct mipi_port_state_s { int device_ready; int irq_status; diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h index 85cb61e341920..ad74487445191 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h @@ -21,7 +21,6 @@ #include "isys_public.h" #else -typedef struct input_system_state_s input_system_state_t; typedef struct receiver_state_s receiver_state_t; /*! Read the state of INPUT_SYSTEM[ID] @@ -31,9 +30,6 @@ typedef struct receiver_state_s receiver_state_t; \return none, state = INPUT_SYSTEM[ID].state */ -void input_system_get_state( - const input_system_ID_t ID, - input_system_state_t *state); /*! Read the state of RECEIVER[ID] diff --git a/drivers/staging/media/atomisp/pci/isp2401_input_system_local.h b/drivers/staging/media/atomisp/pci/isp2401_input_system_local.h index 74bfa10e670e3..7c7297b9c146b 100644 --- a/drivers/staging/media/atomisp/pci/isp2401_input_system_local.h +++ b/drivers/staging/media/atomisp/pci/isp2401_input_system_local.h @@ -66,13 +66,5 @@ typedef enum { /* The number of stores for compressed format types */ #define N_MIPI_COMPRESSOR_CONTEXT (N_RX_CHANNEL_ID * N_MIPI_FORMAT_CUSTOM) -typedef struct input_system_state_s input_system_state_t; -struct input_system_state_s { - ibuf_ctrl_state_t ibuf_ctrl_state[N_IBUF_CTRL_ID]; - csi_rx_fe_ctrl_state_t csi_rx_fe_ctrl_state[N_CSI_RX_FRONTEND_ID]; - csi_rx_be_ctrl_state_t csi_rx_be_ctrl_state[N_CSI_RX_BACKEND_ID]; - pixelgen_ctrl_state_t pixelgen_ctrl_state[N_PIXELGEN_ID]; - stream2mmio_state_t stream2mmio_state[N_STREAM2MMIO_ID]; - isys_irqc_state_t isys_irqc_state[N_ISYS_IRQ_ID]; -}; + #endif /* __INPUT_SYSTEM_LOCAL_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/isp2401_input_system_private.h b/drivers/staging/media/atomisp/pci/isp2401_input_system_private.h index e4c76428f6dd7..f3fdd9a2a5e68 100644 --- a/drivers/staging/media/atomisp/pci/isp2401_input_system_private.h +++ b/drivers/staging/media/atomisp/pci/isp2401_input_system_private.h @@ -231,112 +231,4 @@ static inline void ibuf_ctrl_dump_state(const ibuf_ctrl_ID_t ID, } } -static inline input_system_err_t -input_system_get_state(const input_system_ID_t ID, - input_system_state_t *state) -{ - u32 i; - - (void)(ID); - - /* get the states of all CSI RX frontend devices */ - for (i = 0; i < N_CSI_RX_FRONTEND_ID; i++) { - csi_rx_fe_ctrl_get_state( - (csi_rx_frontend_ID_t)i, - &state->csi_rx_fe_ctrl_state[i]); - } - - /* get the states of all CIS RX backend devices */ - for (i = 0; i < N_CSI_RX_BACKEND_ID; i++) { - csi_rx_be_ctrl_get_state( - (csi_rx_backend_ID_t)i, - &state->csi_rx_be_ctrl_state[i]); - } - - /* get the states of all pixelgen devices */ - for (i = 0; i < N_PIXELGEN_ID; i++) { - pixelgen_ctrl_get_state( - (pixelgen_ID_t)i, - &state->pixelgen_ctrl_state[i]); - } - - /* get the states of all stream2mmio devices */ - for (i = 0; i < N_STREAM2MMIO_ID; i++) { - stream2mmio_get_state( - (stream2mmio_ID_t)i, - &state->stream2mmio_state[i]); - } - - /* get the states of all ibuf-controller devices */ - for (i = 0; i < N_IBUF_CTRL_ID; i++) { - ibuf_ctrl_get_state( - (ibuf_ctrl_ID_t)i, - &state->ibuf_ctrl_state[i]); - } - - /* get the states of all isys irq controllers */ - for (i = 0; i < N_ISYS_IRQ_ID; i++) { - isys_irqc_state_get((isys_irq_ID_t)i, &state->isys_irqc_state[i]); - } - - /* TODO: get the states of all ISYS2401 DMA devices */ - for (i = 0; i < N_ISYS2401_DMA_ID; i++) { - } - - return INPUT_SYSTEM_ERR_NO_ERROR; -} - -static inline void input_system_dump_state(const input_system_ID_t ID, - input_system_state_t *state) -{ - u32 i; - - (void)(ID); - - /* dump the states of all CSI RX frontend devices */ - for (i = 0; i < N_CSI_RX_FRONTEND_ID; i++) { - csi_rx_fe_ctrl_dump_state( - (csi_rx_frontend_ID_t)i, - &state->csi_rx_fe_ctrl_state[i]); - } - - /* dump the states of all CIS RX backend devices */ - for (i = 0; i < N_CSI_RX_BACKEND_ID; i++) { - csi_rx_be_ctrl_dump_state( - (csi_rx_backend_ID_t)i, - &state->csi_rx_be_ctrl_state[i]); - } - - /* dump the states of all pixelgen devices */ - for (i = 0; i < N_PIXELGEN_ID; i++) { - pixelgen_ctrl_dump_state( - (pixelgen_ID_t)i, - &state->pixelgen_ctrl_state[i]); - } - - /* dump the states of all st2mmio devices */ - for (i = 0; i < N_STREAM2MMIO_ID; i++) { - stream2mmio_dump_state( - (stream2mmio_ID_t)i, - &state->stream2mmio_state[i]); - } - - /* dump the states of all ibuf-controller devices */ - for (i = 0; i < N_IBUF_CTRL_ID; i++) { - ibuf_ctrl_dump_state( - (ibuf_ctrl_ID_t)i, - &state->ibuf_ctrl_state[i]); - } - - /* dump the states of all isys irq controllers */ - for (i = 0; i < N_ISYS_IRQ_ID; i++) { - isys_irqc_state_dump((isys_irq_ID_t)i, &state->isys_irqc_state[i]); - } - - /* TODO: dump the states of all ISYS2401 DMA devices */ - for (i = 0; i < N_ISYS2401_DMA_ID; i++) { - } - - return; -} #endif /* __INPUT_SYSTEM_PRIVATE_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h index efa1362948364..b74ab50ea01e3 100644 --- a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h +++ b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h @@ -261,12 +261,6 @@ void ia_css_debug_dump_all_fifo_state(void); */ void ia_css_debug_dump_rx_state(void); -/*! @brief Dump the input system state to the output - * Dumps the input system state to tracing output. - * @return None - */ -void ia_css_debug_dump_isys_state(void); - /*! @brief Dump the frame info to the trace output * Dumps the frame info to tracing output. * @param[in] frame pointer to struct ia_css_frame diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c index cf66a40bd6a44..d40ed9c60f1dc 100644 --- a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c +++ b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c @@ -1799,258 +1799,6 @@ void ia_css_debug_dump_sp_sw_debug_info(void) return; } -#if !defined(ISP2401) -static void debug_print_isys_capture_unit_state(capture_unit_state_t *state) -{ - assert(state); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Packet_Length", state->Packet_Length); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Received_Length", state->Received_Length); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Received_Short_Packets", - state->Received_Short_Packets); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Received_Long_Packets", - state->Received_Long_Packets); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Last_Command", state->Last_Command); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Next_Command", state->Next_Command); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Last_Acknowledge", state->Last_Acknowledge); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Next_Acknowledge", state->Next_Acknowledge); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "FSM_State_Info", state->FSM_State_Info); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "StartMode", state->StartMode); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Start_Addr", state->Start_Addr); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Mem_Region_Size", state->Mem_Region_Size); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Num_Mem_Regions", state->Num_Mem_Regions); - return; -} - -static void debug_print_isys_acquisition_unit_state( - acquisition_unit_state_t *state) -{ - assert(state); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Received_Short_Packets", - state->Received_Short_Packets); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Received_Long_Packets", - state->Received_Long_Packets); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Last_Command", state->Last_Command); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Next_Command", state->Next_Command); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Last_Acknowledge", state->Last_Acknowledge); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Next_Acknowledge", state->Next_Acknowledge); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "FSM_State_Info", state->FSM_State_Info); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Int_Cntr_Info", state->Int_Cntr_Info); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Start_Addr", state->Start_Addr); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Mem_Region_Size", state->Mem_Region_Size); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Num_Mem_Regions", state->Num_Mem_Regions); -} - -static void debug_print_isys_ctrl_unit_state(ctrl_unit_state_t *state) -{ - assert(state); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "last_cmd", state->last_cmd); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "next_cmd", state->next_cmd); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "last_ack", state->last_ack); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "next_ack", state->next_ack); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "top_fsm_state", state->top_fsm_state); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "captA_fsm_state", state->captA_fsm_state); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "captB_fsm_state", state->captB_fsm_state); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "captC_fsm_state", state->captC_fsm_state); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "acq_fsm_state", state->acq_fsm_state); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "captA_start_addr", state->captA_start_addr); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "captB_start_addr", state->captB_start_addr); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "captC_start_addr", state->captC_start_addr); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "captA_mem_region_size", - state->captA_mem_region_size); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "captB_mem_region_size", - state->captB_mem_region_size); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "captC_mem_region_size", - state->captC_mem_region_size); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "captA_num_mem_regions", - state->captA_num_mem_regions); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "captB_num_mem_regions", - state->captB_num_mem_regions); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "captC_num_mem_regions", - state->captC_num_mem_regions); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "acq_start_addr", state->acq_start_addr); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "acq_mem_region_size", state->acq_mem_region_size); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "acq_num_mem_regions", state->acq_num_mem_regions); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "capt_reserve_one_mem_region", - state->capt_reserve_one_mem_region); - - return; -} - -static void debug_print_isys_state(input_system_state_t *state) -{ - int i; - - assert(state); - ia_css_debug_dtrace(2, "InputSystem State:\n"); - - /* configuration */ - ia_css_debug_dtrace(2, "\tConfiguration:\n"); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "str_multiCastA_sel", state->str_multicastA_sel); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "str_multicastB_sel", state->str_multicastB_sel); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "str_multicastC_sel", state->str_multicastC_sel); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "str_mux_sel", state->str_mux_sel); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "str_mon_status", state->str_mon_status); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "str_mon_irq_cond", state->str_mon_irq_cond); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "str_mon_irq_en", state->str_mon_irq_en); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "isys_srst", state->isys_srst); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "isys_slv_reg_srst", state->isys_slv_reg_srst); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "str_deint_portA_cnt", state->str_deint_portA_cnt); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "str_deint_portB_cnd", state->str_deint_portB_cnt); - /* end of configuration */ - - /* capture unit state */ - for (i = 0; i < N_CAPTURE_UNIT_ID; i++) { - capture_unit_state_t *capture_unit_state; - - ia_css_debug_dtrace(2, "\tCaptureUnit %d State:\n", i); - - capture_unit_state = &state->capture_unit[i]; - debug_print_isys_capture_unit_state(capture_unit_state); - } - /* end of capture unit state */ - - /* acquisition unit state */ - for (i = 0; i < N_ACQUISITION_UNIT_ID; i++) { - acquisition_unit_state_t *acquisition_unit_state; - - ia_css_debug_dtrace(2, "\tAcquisitionUnit %d State:\n", i); - - acquisition_unit_state = &state->acquisition_unit[i]; - debug_print_isys_acquisition_unit_state(acquisition_unit_state); - } - /* end of acquisition unit state */ - - /* control unit state */ - for (i = 0; i < N_CTRL_UNIT_ID; i++) { - ia_css_debug_dtrace(2, "\tControlUnit %d State:\n", i); - - debug_print_isys_ctrl_unit_state(&state->ctrl_unit_state[i]); - } - /* end of control unit state */ -} -#endif - -void ia_css_debug_dump_isys_state(void) -{ - static input_system_state_t state; - - input_system_get_state(INPUT_SYSTEM0_ID, &state); - -#ifndef ISP2401 - debug_print_isys_state(&state); -#else - input_system_dump_state(INPUT_SYSTEM0_ID, &state); -#endif -} - void ia_css_debug_dump_debug_info(const char *context) { if (!context) @@ -2075,8 +1823,6 @@ void ia_css_debug_dump_debug_info(const char *context) if (!IS_ISP2401) { struct irq_controller_state state; - ia_css_debug_dump_isys_state(); - irq_controller_get_state(IRQ2_ID, &state); ia_css_debug_dtrace(2, "\t%-32s:\n", @@ -2097,8 +1843,6 @@ void ia_css_debug_dump_debug_info(const char *context) ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "irq_level_not_pulse", state.irq_level_not_pulse); - } else { - ia_css_debug_dump_isys_state(); } ia_css_debug_tagger_state(); diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index 4b3fa6d93fe0a..67c581d3c1a63 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -7623,7 +7623,6 @@ void ia_css_stream_request_flash(struct ia_css_stream *stream) if (!sh_css_write_host2sp_command(host2sp_cmd_start_flash)) { IA_CSS_ERROR("Call to 'sh-css_write_host2sp_command()' failed"); ia_css_debug_dump_sp_sw_debug_info(); - ia_css_debug_dump_debug_info(NULL); } } else { IA_CSS_LOG("SP is not running!"); @@ -9035,7 +9034,6 @@ ia_css_stop_sp(void) if (!sh_css_write_host2sp_command(host2sp_cmd_terminate)) { IA_CSS_ERROR("Call to 'sh-css_write_host2sp_command()' failed"); ia_css_debug_dump_sp_sw_debug_info(); - ia_css_debug_dump_debug_info(NULL); } sh_css_sp_set_sp_running(false); -- GitLab From 8fc67b18fa1ccaf8c35919f27ccb119fdc2a35a8 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Thu, 13 Jul 2023 12:02:22 +0200 Subject: [PATCH 0334/1451] media: atomisp: Make two individual enum to define the MIPI format The original mipi_format_t represents the MIPI format settings for both atomisp with the same name and the enum member was controlled by #if defined(ISP2401). However, if we want to make this driver generic, this enum should be individually defined for them. Since the format type is redefined, the format setting function ia_css_isys_set_fmt_type() should be reworked for ISP2400 and ISP2401 called ia_css_isys_2400_set_fmt_type() and ia_css_isys_2401_set_fmt_type() . Additionally, the function called is_mipi_format_yuv420() isn't used by any functions so it can be removed. Link: https://lore.kernel.org/r/20230713100231.308923-3-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../hive_isp_css_common/host/input_system.c | 13 - .../atomisp/pci/isp2400_input_system_local.h | 68 +++--- .../atomisp/pci/isp2400_input_system_public.h | 2 - .../atomisp/pci/isp2401_input_system_local.h | 74 +++--- .../media/atomisp/pci/runtime/isys/src/rx.c | 226 ++++++++++++------ .../pci/runtime/isys/src/virtual_isys.c | 6 +- 6 files changed, 224 insertions(+), 165 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c index 09aca4e3db226..7a74c679ed923 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c @@ -186,19 +186,6 @@ void receiver_get_state( _HRT_CSS_RECEIVER_BE_IRQ_CLEAR_REG_IDX); } -bool is_mipi_format_yuv420( - const mipi_format_t mipi_format) -{ - bool is_yuv420 = ( - (mipi_format == MIPI_FORMAT_YUV420_8) || - (mipi_format == MIPI_FORMAT_YUV420_10) || - (mipi_format == MIPI_FORMAT_YUV420_8_SHIFT) || - (mipi_format == MIPI_FORMAT_YUV420_10_SHIFT)); - /* MIPI_FORMAT_YUV420_8_LEGACY is not YUV420 */ - - return is_yuv420; -} - void receiver_set_compression( const rx_ID_t ID, const unsigned int cfg_ID, diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h index 8701abc4c9919..847ad7554eb7d 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h @@ -168,40 +168,40 @@ typedef struct acquisition_unit_state_s acquisition_unit_state_t; typedef struct ctrl_unit_state_s ctrl_unit_state_t; typedef enum { - MIPI_FORMAT_RGB888 = 0, - MIPI_FORMAT_RGB555, - MIPI_FORMAT_RGB444, - MIPI_FORMAT_RGB565, - MIPI_FORMAT_RGB666, - MIPI_FORMAT_RAW8, /* 5 */ - MIPI_FORMAT_RAW10, - MIPI_FORMAT_RAW6, - MIPI_FORMAT_RAW7, - MIPI_FORMAT_RAW12, - MIPI_FORMAT_RAW14, /* 10 */ - MIPI_FORMAT_YUV420_8, - MIPI_FORMAT_YUV420_10, - MIPI_FORMAT_YUV422_8, - MIPI_FORMAT_YUV422_10, - MIPI_FORMAT_CUSTOM0, /* 15 */ - MIPI_FORMAT_YUV420_8_LEGACY, - MIPI_FORMAT_EMBEDDED, - MIPI_FORMAT_CUSTOM1, - MIPI_FORMAT_CUSTOM2, - MIPI_FORMAT_CUSTOM3, /* 20 */ - MIPI_FORMAT_CUSTOM4, - MIPI_FORMAT_CUSTOM5, - MIPI_FORMAT_CUSTOM6, - MIPI_FORMAT_CUSTOM7, - MIPI_FORMAT_YUV420_8_SHIFT, /* 25 */ - MIPI_FORMAT_YUV420_10_SHIFT, - MIPI_FORMAT_RAW16, - MIPI_FORMAT_RAW18, - N_MIPI_FORMAT, -} mipi_format_t; - -#define MIPI_FORMAT_JPEG MIPI_FORMAT_CUSTOM0 -#define MIPI_FORMAT_BINARY_8 MIPI_FORMAT_CUSTOM0 + MIPI_FORMAT_2400_RGB888 = 0, + MIPI_FORMAT_2400_RGB555, + MIPI_FORMAT_2400_RGB444, + MIPI_FORMAT_2400_RGB565, + MIPI_FORMAT_2400_RGB666, + MIPI_FORMAT_2400_RAW8, /* 5 */ + MIPI_FORMAT_2400_RAW10, + MIPI_FORMAT_2400_RAW6, + MIPI_FORMAT_2400_RAW7, + MIPI_FORMAT_2400_RAW12, + MIPI_FORMAT_2400_RAW14, /* 10 */ + MIPI_FORMAT_2400_YUV420_8, + MIPI_FORMAT_2400_YUV420_10, + MIPI_FORMAT_2400_YUV422_8, + MIPI_FORMAT_2400_YUV422_10, + MIPI_FORMAT_2400_CUSTOM0, /* 15 */ + MIPI_FORMAT_2400_YUV420_8_LEGACY, + MIPI_FORMAT_2400_EMBEDDED, + MIPI_FORMAT_2400_CUSTOM1, + MIPI_FORMAT_2400_CUSTOM2, + MIPI_FORMAT_2400_CUSTOM3, /* 20 */ + MIPI_FORMAT_2400_CUSTOM4, + MIPI_FORMAT_2400_CUSTOM5, + MIPI_FORMAT_2400_CUSTOM6, + MIPI_FORMAT_2400_CUSTOM7, + MIPI_FORMAT_2400_YUV420_8_SHIFT, /* 25 */ + MIPI_FORMAT_2400_YUV420_10_SHIFT, + MIPI_FORMAT_2400_RAW16, + MIPI_FORMAT_2400_RAW18, + N_MIPI_FORMAT_2400, +} mipi_format_2400_t; + +#define MIPI_FORMAT_JPEG MIPI_FORMAT_2400_CUSTOM0 +#define MIPI_FORMAT_BINARY_8 MIPI_FORMAT_2400_CUSTOM0 #define N_MIPI_FORMAT_CUSTOM 8 /* The number of stores for compressed format types */ diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h index ad74487445191..6477be44a8159 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h @@ -48,8 +48,6 @@ void receiver_get_state( \return mipi_format == YUV420 */ -bool is_mipi_format_yuv420( - const mipi_format_t mipi_format); /*! Set compression parameters for cfg[cfg_ID] of RECEIVER[ID] diff --git a/drivers/staging/media/atomisp/pci/isp2401_input_system_local.h b/drivers/staging/media/atomisp/pci/isp2401_input_system_local.h index 7c7297b9c146b..361a615bbcade 100644 --- a/drivers/staging/media/atomisp/pci/isp2401_input_system_local.h +++ b/drivers/staging/media/atomisp/pci/isp2401_input_system_local.h @@ -22,45 +22,45 @@ #include "isys_irq.h" typedef enum { - MIPI_FORMAT_SHORT1 = 0x08, - MIPI_FORMAT_SHORT2, - MIPI_FORMAT_SHORT3, - MIPI_FORMAT_SHORT4, - MIPI_FORMAT_SHORT5, - MIPI_FORMAT_SHORT6, - MIPI_FORMAT_SHORT7, - MIPI_FORMAT_SHORT8, - MIPI_FORMAT_EMBEDDED = 0x12, - MIPI_FORMAT_YUV420_8 = 0x18, - MIPI_FORMAT_YUV420_10, - MIPI_FORMAT_YUV420_8_LEGACY, - MIPI_FORMAT_YUV420_8_SHIFT = 0x1C, - MIPI_FORMAT_YUV420_10_SHIFT, - MIPI_FORMAT_YUV422_8 = 0x1E, - MIPI_FORMAT_YUV422_10, - MIPI_FORMAT_RGB444 = 0x20, - MIPI_FORMAT_RGB555, - MIPI_FORMAT_RGB565, - MIPI_FORMAT_RGB666, - MIPI_FORMAT_RGB888, - MIPI_FORMAT_RAW6 = 0x28, - MIPI_FORMAT_RAW7, - MIPI_FORMAT_RAW8, - MIPI_FORMAT_RAW10, - MIPI_FORMAT_RAW12, - MIPI_FORMAT_RAW14, - MIPI_FORMAT_CUSTOM0 = 0x30, - MIPI_FORMAT_CUSTOM1, - MIPI_FORMAT_CUSTOM2, - MIPI_FORMAT_CUSTOM3, - MIPI_FORMAT_CUSTOM4, - MIPI_FORMAT_CUSTOM5, - MIPI_FORMAT_CUSTOM6, - MIPI_FORMAT_CUSTOM7, + MIPI_FORMAT_2401_SHORT1 = 0x08, + MIPI_FORMAT_2401_SHORT2, + MIPI_FORMAT_2401_SHORT3, + MIPI_FORMAT_2401_SHORT4, + MIPI_FORMAT_2401_SHORT5, + MIPI_FORMAT_2401_SHORT6, + MIPI_FORMAT_2401_SHORT7, + MIPI_FORMAT_2401_SHORT8, + MIPI_FORMAT_2401_EMBEDDED = 0x12, + MIPI_FORMAT_2401_YUV420_8 = 0x18, + MIPI_FORMAT_2401_YUV420_10, + MIPI_FORMAT_2401_YUV420_8_LEGACY, + MIPI_FORMAT_2401_YUV420_8_SHIFT = 0x1C, + MIPI_FORMAT_2401_YUV420_10_SHIFT, + MIPI_FORMAT_2401_YUV422_8 = 0x1E, + MIPI_FORMAT_2401_YUV422_10, + MIPI_FORMAT_2401_RGB444 = 0x20, + MIPI_FORMAT_2401_RGB555, + MIPI_FORMAT_2401_RGB565, + MIPI_FORMAT_2401_RGB666, + MIPI_FORMAT_2401_RGB888, + MIPI_FORMAT_2401_RAW6 = 0x28, + MIPI_FORMAT_2401_RAW7, + MIPI_FORMAT_2401_RAW8, + MIPI_FORMAT_2401_RAW10, + MIPI_FORMAT_2401_RAW12, + MIPI_FORMAT_2401_RAW14, + MIPI_FORMAT_2401_CUSTOM0 = 0x30, + MIPI_FORMAT_2401_CUSTOM1, + MIPI_FORMAT_2401_CUSTOM2, + MIPI_FORMAT_2401_CUSTOM3, + MIPI_FORMAT_2401_CUSTOM4, + MIPI_FORMAT_2401_CUSTOM5, + MIPI_FORMAT_2401_CUSTOM6, + MIPI_FORMAT_2401_CUSTOM7, //MIPI_FORMAT_RAW16, /*not supported by 2401*/ //MIPI_FORMAT_RAW18, - N_MIPI_FORMAT -} mipi_format_t; + N_MIPI_FORMAT_2401 +} mipi_format_2401_t; #define N_MIPI_FORMAT_CUSTOM 8 diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c index af153c3fb86d3..b58f4fd4a35c9 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c @@ -211,142 +211,160 @@ void ia_css_isys_rx_clear_irq_info(enum mipi_port_id port, } #endif /* #if !defined(ISP2401) */ -int ia_css_isys_convert_stream_format_to_mipi_format( - enum atomisp_input_format input_format, - mipi_predictor_t compression, - unsigned int *fmt_type) +#if !defined(ISP2401) +static int ia_css_isys_2400_set_fmt_type(enum atomisp_input_format input_format, + unsigned int *fmt_type) { - assert(fmt_type); - /* - * Custom (user defined) modes. Used for compressed - * MIPI transfers - * - * Checkpatch thinks the indent before "if" is suspect - * I think the only suspect part is the missing "else" - * because of the return. - */ - if (compression != MIPI_PREDICTOR_NONE) { - switch (input_format) { - case ATOMISP_INPUT_FORMAT_RAW_6: - *fmt_type = 6; - break; - case ATOMISP_INPUT_FORMAT_RAW_7: - *fmt_type = 7; - break; - case ATOMISP_INPUT_FORMAT_RAW_8: - *fmt_type = 8; - break; - case ATOMISP_INPUT_FORMAT_RAW_10: - *fmt_type = 10; - break; - case ATOMISP_INPUT_FORMAT_RAW_12: - *fmt_type = 12; - break; - case ATOMISP_INPUT_FORMAT_RAW_14: - *fmt_type = 14; - break; - case ATOMISP_INPUT_FORMAT_RAW_16: - *fmt_type = 16; - break; - default: - return -EINVAL; - } - return 0; - } - /* - * This mapping comes from the Arasan CSS function spec - * (CSS_func_spec1.08_ahb_sep29_08.pdf). - * - * MW: For some reason the mapping is not 1-to-1 - */ switch (input_format) { case ATOMISP_INPUT_FORMAT_RGB_888: - *fmt_type = MIPI_FORMAT_RGB888; + *fmt_type = MIPI_FORMAT_2400_RGB888; break; case ATOMISP_INPUT_FORMAT_RGB_555: - *fmt_type = MIPI_FORMAT_RGB555; + *fmt_type = MIPI_FORMAT_2400_RGB555; break; case ATOMISP_INPUT_FORMAT_RGB_444: - *fmt_type = MIPI_FORMAT_RGB444; + *fmt_type = MIPI_FORMAT_2400_RGB444; break; case ATOMISP_INPUT_FORMAT_RGB_565: - *fmt_type = MIPI_FORMAT_RGB565; + *fmt_type = MIPI_FORMAT_2400_RGB565; break; case ATOMISP_INPUT_FORMAT_RGB_666: - *fmt_type = MIPI_FORMAT_RGB666; + *fmt_type = MIPI_FORMAT_2400_RGB666; break; case ATOMISP_INPUT_FORMAT_RAW_8: - *fmt_type = MIPI_FORMAT_RAW8; + *fmt_type = MIPI_FORMAT_2400_RAW8; break; case ATOMISP_INPUT_FORMAT_RAW_10: - *fmt_type = MIPI_FORMAT_RAW10; + *fmt_type = MIPI_FORMAT_2400_RAW10; break; case ATOMISP_INPUT_FORMAT_RAW_6: - *fmt_type = MIPI_FORMAT_RAW6; + *fmt_type = MIPI_FORMAT_2400_RAW6; break; case ATOMISP_INPUT_FORMAT_RAW_7: - *fmt_type = MIPI_FORMAT_RAW7; + *fmt_type = MIPI_FORMAT_2400_RAW7; break; case ATOMISP_INPUT_FORMAT_RAW_12: - *fmt_type = MIPI_FORMAT_RAW12; + *fmt_type = MIPI_FORMAT_2400_RAW12; break; case ATOMISP_INPUT_FORMAT_RAW_14: - *fmt_type = MIPI_FORMAT_RAW14; + *fmt_type = MIPI_FORMAT_2400_RAW14; break; case ATOMISP_INPUT_FORMAT_YUV420_8: - *fmt_type = MIPI_FORMAT_YUV420_8; + *fmt_type = MIPI_FORMAT_2400_YUV420_8; break; case ATOMISP_INPUT_FORMAT_YUV420_10: - *fmt_type = MIPI_FORMAT_YUV420_10; + *fmt_type = MIPI_FORMAT_2400_YUV420_10; break; case ATOMISP_INPUT_FORMAT_YUV422_8: - *fmt_type = MIPI_FORMAT_YUV422_8; + *fmt_type = MIPI_FORMAT_2400_YUV422_8; break; case ATOMISP_INPUT_FORMAT_YUV422_10: - *fmt_type = MIPI_FORMAT_YUV422_10; + *fmt_type = MIPI_FORMAT_2400_YUV422_10; break; case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY: - *fmt_type = MIPI_FORMAT_YUV420_8_LEGACY; + *fmt_type = MIPI_FORMAT_2400_YUV420_8_LEGACY; break; case ATOMISP_INPUT_FORMAT_EMBEDDED: - *fmt_type = MIPI_FORMAT_EMBEDDED; + *fmt_type = MIPI_FORMAT_2400_EMBEDDED; break; -#ifndef ISP2401 case ATOMISP_INPUT_FORMAT_RAW_16: /* This is not specified by Arasan, so we use * 17 for now. */ - *fmt_type = MIPI_FORMAT_RAW16; + *fmt_type = MIPI_FORMAT_2400_RAW16; break; case ATOMISP_INPUT_FORMAT_BINARY_8: *fmt_type = MIPI_FORMAT_BINARY_8; break; -#else + case ATOMISP_INPUT_FORMAT_YUV420_16: + case ATOMISP_INPUT_FORMAT_YUV422_16: + default: + return -EINVAL; + } + return 0; +} +#endif /* #ifndef ISP2401 */ + +#if defined(ISP2401) +static int ia_css_isys_2401_set_fmt_type(enum atomisp_input_format input_format, + unsigned int *fmt_type) +{ + switch (input_format) { + case ATOMISP_INPUT_FORMAT_RGB_888: + *fmt_type = MIPI_FORMAT_2401_RGB888; + break; + case ATOMISP_INPUT_FORMAT_RGB_555: + *fmt_type = MIPI_FORMAT_2401_RGB555; + break; + case ATOMISP_INPUT_FORMAT_RGB_444: + *fmt_type = MIPI_FORMAT_2401_RGB444; + break; + case ATOMISP_INPUT_FORMAT_RGB_565: + *fmt_type = MIPI_FORMAT_2401_RGB565; + break; + case ATOMISP_INPUT_FORMAT_RGB_666: + *fmt_type = MIPI_FORMAT_2401_RGB666; + break; + case ATOMISP_INPUT_FORMAT_RAW_8: + *fmt_type = MIPI_FORMAT_2401_RAW8; + break; + case ATOMISP_INPUT_FORMAT_RAW_10: + *fmt_type = MIPI_FORMAT_2401_RAW10; + break; + case ATOMISP_INPUT_FORMAT_RAW_6: + *fmt_type = MIPI_FORMAT_2401_RAW6; + break; + case ATOMISP_INPUT_FORMAT_RAW_7: + *fmt_type = MIPI_FORMAT_2401_RAW7; + break; + case ATOMISP_INPUT_FORMAT_RAW_12: + *fmt_type = MIPI_FORMAT_2401_RAW12; + break; + case ATOMISP_INPUT_FORMAT_RAW_14: + *fmt_type = MIPI_FORMAT_2401_RAW14; + break; + case ATOMISP_INPUT_FORMAT_YUV420_8: + *fmt_type = MIPI_FORMAT_2401_YUV420_8; + break; + case ATOMISP_INPUT_FORMAT_YUV420_10: + *fmt_type = MIPI_FORMAT_2401_YUV420_10; + break; + case ATOMISP_INPUT_FORMAT_YUV422_8: + *fmt_type = MIPI_FORMAT_2401_YUV422_8; + break; + case ATOMISP_INPUT_FORMAT_YUV422_10: + *fmt_type = MIPI_FORMAT_2401_YUV422_10; + break; + case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY: + *fmt_type = MIPI_FORMAT_2401_YUV420_8_LEGACY; + break; + case ATOMISP_INPUT_FORMAT_EMBEDDED: + *fmt_type = MIPI_FORMAT_2401_EMBEDDED; + break; case ATOMISP_INPUT_FORMAT_USER_DEF1: - *fmt_type = MIPI_FORMAT_CUSTOM0; + *fmt_type = MIPI_FORMAT_2401_CUSTOM0; break; case ATOMISP_INPUT_FORMAT_USER_DEF2: - *fmt_type = MIPI_FORMAT_CUSTOM1; + *fmt_type = MIPI_FORMAT_2401_CUSTOM1; break; case ATOMISP_INPUT_FORMAT_USER_DEF3: - *fmt_type = MIPI_FORMAT_CUSTOM2; + *fmt_type = MIPI_FORMAT_2401_CUSTOM2; break; case ATOMISP_INPUT_FORMAT_USER_DEF4: - *fmt_type = MIPI_FORMAT_CUSTOM3; + *fmt_type = MIPI_FORMAT_2401_CUSTOM3; break; case ATOMISP_INPUT_FORMAT_USER_DEF5: - *fmt_type = MIPI_FORMAT_CUSTOM4; + *fmt_type = MIPI_FORMAT_2401_CUSTOM4; break; case ATOMISP_INPUT_FORMAT_USER_DEF6: - *fmt_type = MIPI_FORMAT_CUSTOM5; + *fmt_type = MIPI_FORMAT_2401_CUSTOM5; break; case ATOMISP_INPUT_FORMAT_USER_DEF7: - *fmt_type = MIPI_FORMAT_CUSTOM6; + *fmt_type = MIPI_FORMAT_2401_CUSTOM6; break; case ATOMISP_INPUT_FORMAT_USER_DEF8: - *fmt_type = MIPI_FORMAT_CUSTOM7; + *fmt_type = MIPI_FORMAT_2401_CUSTOM7; break; -#endif case ATOMISP_INPUT_FORMAT_YUV420_16: case ATOMISP_INPUT_FORMAT_YUV422_16: @@ -355,6 +373,62 @@ int ia_css_isys_convert_stream_format_to_mipi_format( } return 0; } +#endif /* #ifdef ISP2401 */ + +int ia_css_isys_convert_stream_format_to_mipi_format( + enum atomisp_input_format input_format, + mipi_predictor_t compression, + unsigned int *fmt_type) +{ + assert(fmt_type); + /* + * Custom (user defined) modes. Used for compressed + * MIPI transfers + * + * Checkpatch thinks the indent before "if" is suspect + * I think the only suspect part is the missing "else" + * because of the return. + */ + if (compression != MIPI_PREDICTOR_NONE) { + switch (input_format) { + case ATOMISP_INPUT_FORMAT_RAW_6: + *fmt_type = 6; + break; + case ATOMISP_INPUT_FORMAT_RAW_7: + *fmt_type = 7; + break; + case ATOMISP_INPUT_FORMAT_RAW_8: + *fmt_type = 8; + break; + case ATOMISP_INPUT_FORMAT_RAW_10: + *fmt_type = 10; + break; + case ATOMISP_INPUT_FORMAT_RAW_12: + *fmt_type = 12; + break; + case ATOMISP_INPUT_FORMAT_RAW_14: + *fmt_type = 14; + break; + case ATOMISP_INPUT_FORMAT_RAW_16: + *fmt_type = 16; + break; + default: + return -EINVAL; + } + return 0; + } + /* + * This mapping comes from the Arasan CSS function spec + * (CSS_func_spec1.08_ahb_sep29_08.pdf). + * + * MW: For some reason the mapping is not 1-to-1 + */ +#if defined(ISP2401) + return ia_css_isys_2401_set_fmt_type(input_format, fmt_type); +#else + return ia_css_isys_2400_set_fmt_type(input_format, fmt_type); +#endif +} #if defined(ISP2401) static mipi_predictor_t sh_css_csi2_compression_type_2_mipi_predictor( diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c index 8fc7746f86390..def8a0b1d2ec1 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c @@ -689,7 +689,7 @@ static bool calculate_be_cfg( cfg->csi_mipi_cfg.comp_scheme = isys_cfg->csi_port_attr.comp_scheme; cfg->csi_mipi_cfg.comp_predictor = isys_cfg->csi_port_attr.comp_predictor; cfg->csi_mipi_cfg.comp_bit_idx = cfg->csi_mipi_cfg.data_type - - MIPI_FORMAT_CUSTOM0; + MIPI_FORMAT_2401_CUSTOM0; } return true; @@ -856,10 +856,10 @@ static csi_mipi_packet_type_t get_csi_mipi_packet_type( packet_type = CSI_MIPI_PACKET_TYPE_RESERVED; - if (data_type >= 0 && data_type <= MIPI_FORMAT_SHORT8) + if (data_type >= 0 && data_type <= MIPI_FORMAT_2401_SHORT8) packet_type = CSI_MIPI_PACKET_TYPE_SHORT; - if (data_type > MIPI_FORMAT_SHORT8 && data_type <= N_MIPI_FORMAT) + if (data_type > MIPI_FORMAT_2401_SHORT8 && data_type <= N_MIPI_FORMAT_2401) packet_type = CSI_MIPI_PACKET_TYPE_LONG; return packet_type; -- GitLab From 2aea82b03cd4e57f3d639d3bedb0876082416052 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Thu, 13 Jul 2023 12:02:23 +0200 Subject: [PATCH 0335/1451] media: atomisp: Included both input system headers Included necessary input system header files (local, private, public scopes) for both types of atomisp. There is also a conflict of declaration issue so the unused input_system_state_s is removed. Link: https://lore.kernel.org/r/20230713100231.308923-4-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/input_system_local.h | 7 ++----- drivers/staging/media/atomisp/pci/input_system_private.h | 7 ++----- drivers/staging/media/atomisp/pci/input_system_public.h | 4 +--- .../staging/media/atomisp/pci/isp2400_input_system_local.h | 4 ++-- .../media/atomisp/pci/isp2400_input_system_private.h | 4 ++-- .../media/atomisp/pci/isp2400_input_system_public.h | 7 ++----- .../staging/media/atomisp/pci/isp2401_input_system_local.h | 4 ++-- .../media/atomisp/pci/isp2401_input_system_private.h | 4 ++-- 8 files changed, 15 insertions(+), 26 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/input_system_local.h b/drivers/staging/media/atomisp/pci/input_system_local.h index 357987d629cd3..12f7acfeb79c9 100644 --- a/drivers/staging/media/atomisp/pci/input_system_local.h +++ b/drivers/staging/media/atomisp/pci/input_system_local.h @@ -138,8 +138,5 @@ struct rx_cfg_s { bool is_two_ppc; }; -#ifdef ISP2401 -# include "isp2401_input_system_local.h" -#else -# include "isp2400_input_system_local.h" -#endif +#include "isp2401_input_system_local.h" +#include "isp2400_input_system_local.h" diff --git a/drivers/staging/media/atomisp/pci/input_system_private.h b/drivers/staging/media/atomisp/pci/input_system_private.h index 889f204e77d5b..148ba2ca22904 100644 --- a/drivers/staging/media/atomisp/pci/input_system_private.h +++ b/drivers/staging/media/atomisp/pci/input_system_private.h @@ -4,8 +4,5 @@ * (c) 2020 Mauro Carvalho Chehab */ -#ifdef ISP2401 -# include "isp2401_input_system_private.h" -#else -# include "isp2400_input_system_private.h" -#endif +#include "isp2401_input_system_private.h" +#include "isp2400_input_system_private.h" diff --git a/drivers/staging/media/atomisp/pci/input_system_public.h b/drivers/staging/media/atomisp/pci/input_system_public.h index 3f5167fd66433..06b19434b6c09 100644 --- a/drivers/staging/media/atomisp/pci/input_system_public.h +++ b/drivers/staging/media/atomisp/pci/input_system_public.h @@ -4,6 +4,4 @@ * (c) 2020 Mauro Carvalho Chehab */ -#ifndef ISP2401 -# include "isp2400_input_system_public.h" -#endif +#include "isp2400_input_system_public.h" diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h index 847ad7554eb7d..e7b84fdbb4e03 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h @@ -13,8 +13,8 @@ * more details. */ -#ifndef __INPUT_SYSTEM_LOCAL_H_INCLUDED__ -#define __INPUT_SYSTEM_LOCAL_H_INCLUDED__ +#ifndef __INPUT_SYSTEM_2400_LOCAL_H_INCLUDED__ +#define __INPUT_SYSTEM_2400_LOCAL_H_INCLUDED__ #include "input_system_defs.h" /* HIVE_ISYS_GPREG_MULTICAST_A_IDX,... */ diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_private.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_private.h index 9c39ca2da923c..e011920f00e19 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_private.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_private.h @@ -13,8 +13,8 @@ * more details. */ -#ifndef __INPUT_SYSTEM_PRIVATE_H_INCLUDED__ -#define __INPUT_SYSTEM_PRIVATE_H_INCLUDED__ +#ifndef __INPUT_SYSTEM_2400_PRIVATE_H_INCLUDED__ +#define __INPUT_SYSTEM_2400_PRIVATE_H_INCLUDED__ #include "input_system_public.h" diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h index 6477be44a8159..375c0db84b557 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h @@ -13,13 +13,11 @@ * more details. */ -#ifndef __INPUT_SYSTEM_PUBLIC_H_INCLUDED__ -#define __INPUT_SYSTEM_PUBLIC_H_INCLUDED__ +#ifndef __INPUT_SYSTEM_2400_PUBLIC_H_INCLUDED__ +#define __INPUT_SYSTEM_2400_PUBLIC_H_INCLUDED__ #include -#ifdef ISP2401 #include "isys_public.h" -#else typedef struct receiver_state_s receiver_state_t; @@ -359,6 +357,5 @@ input_system_err_t input_system_gpfifo_channel_cfg( u32 nof_frames, target_cfg2400_t target ); -#endif /* #ifdef ISP2401 */ #endif /* __INPUT_SYSTEM_PUBLIC_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/isp2401_input_system_local.h b/drivers/staging/media/atomisp/pci/isp2401_input_system_local.h index 361a615bbcade..d9a8d575c58e4 100644 --- a/drivers/staging/media/atomisp/pci/isp2401_input_system_local.h +++ b/drivers/staging/media/atomisp/pci/isp2401_input_system_local.h @@ -13,8 +13,8 @@ * more details. */ -#ifndef __INPUT_SYSTEM_LOCAL_H_INCLUDED__ -#define __INPUT_SYSTEM_LOCAL_H_INCLUDED__ +#ifndef __INPUT_SYSTEM_2401_LOCAL_H_INCLUDED__ +#define __INPUT_SYSTEM_2401_LOCAL_H_INCLUDED__ #include "csi_rx.h" #include "pixelgen.h" diff --git a/drivers/staging/media/atomisp/pci/isp2401_input_system_private.h b/drivers/staging/media/atomisp/pci/isp2401_input_system_private.h index f3fdd9a2a5e68..845ed0add027b 100644 --- a/drivers/staging/media/atomisp/pci/isp2401_input_system_private.h +++ b/drivers/staging/media/atomisp/pci/isp2401_input_system_private.h @@ -13,8 +13,8 @@ * more details. */ -#ifndef __INPUT_SYSTEM_PRIVATE_H_INCLUDED__ -#define __INPUT_SYSTEM_PRIVATE_H_INCLUDED__ +#ifndef __INPUT_SYSTEM_2401_PRIVATE_H_INCLUDED__ +#define __INPUT_SYSTEM_2401_PRIVATE_H_INCLUDED__ #include "input_system_public.h" -- GitLab From 7ed0c6c069b6713f9d483605772488082a2b6b7c Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Thu, 13 Jul 2023 12:02:24 +0200 Subject: [PATCH 0336/1451] media: atomisp: css_2401_system: Remove #ifdef ISP2401 to make the driver generic Removed #if defined(2401) to make the driver generic. Link: https://lore.kernel.org/r/20230713100231.308923-5-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/pci/css_2401_system/host/isys_irq_local.h | 3 --- .../media/atomisp/pci/css_2401_system/host/isys_irq_private.h | 2 -- .../media/atomisp/pci/css_2401_system/isys_irq_global.h | 2 -- 3 files changed, 7 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_local.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_local.h index a769871902924..0f585a7e0fa40 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_local.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_local.h @@ -18,8 +18,6 @@ #include -#if defined(ISP2401) - typedef struct isys_irqc_state_s isys_irqc_state_t; struct isys_irqc_state_s { @@ -31,6 +29,5 @@ struct isys_irqc_state_s { /*hrt_data clear; */ /* write-only register */ }; -#endif /* defined(ISP2401) */ #endif /* __ISYS_IRQ_LOCAL_H__ */ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_private.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_private.h index fb168c25bdfc3..d94c8e6add72b 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_private.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_private.h @@ -19,7 +19,6 @@ #include "isys_irq_global.h" #include "isys_irq_local.h" -#if defined(ISP2401) /* -------------------------------------------------------+ | Native command interface (NCI) | @@ -102,6 +101,5 @@ hrt_data isys_irqc_reg_load( /* end of DLI */ -#endif /* defined(ISP2401) */ #endif /* __ISYS_IRQ_PRIVATE_H__ */ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/isys_irq_global.h b/drivers/staging/media/atomisp/pci/css_2401_system/isys_irq_global.h index a81e4d13ac9f5..16336ed730363 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/isys_irq_global.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/isys_irq_global.h @@ -16,7 +16,6 @@ #ifndef __ISYS_IRQ_GLOBAL_H__ #define __ISYS_IRQ_GLOBAL_H__ -#if defined(ISP2401) /* Register offset/index from base location */ #define ISYS_IRQ_EDGE_REG_IDX (0) @@ -31,6 +30,5 @@ #define ISYS_IRQ_CLEAR_REG_VALUE (0xFFFF) #define ISYS_IRQ_ENABLE_REG_VALUE (0xFFFF) -#endif /* defined(ISP2401) */ #endif /* __ISYS_IRQ_GLOBAL_H__ */ -- GitLab From db401104fa02dbd698c051246be2e2855cb0cef8 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Thu, 13 Jul 2023 12:02:25 +0200 Subject: [PATCH 0337/1451] media: atomisp: isys: Removed #if defined(ISP2401) to make driver generic Removed #if defined(ISP2401) to make code generic. Link: https://lore.kernel.org/r/20230713100231.308923-6-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../atomisp/pci/hive_isp_css_include/host/isys_dma_public.h | 2 -- .../atomisp/pci/hive_isp_css_include/host/isys_irq_public.h | 2 -- .../staging/media/atomisp/pci/hive_isp_css_include/isys_irq.h | 2 -- 3 files changed, 6 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_dma_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_dma_public.h index d9b6af898c06b..f18a057adb0f7 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_dma_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_dma_public.h @@ -16,7 +16,6 @@ #ifndef __ISYS_DMA_PUBLIC_H_INCLUDED__ #define __ISYS_DMA_PUBLIC_H_INCLUDED__ -#ifdef ISP2401 #include "system_local.h" #include "type_support.h" @@ -34,6 +33,5 @@ void isys2401_dma_set_max_burst_size( const isys2401_dma_ID_t dma_id, uint32_t max_burst_size); -#endif /* ISP2401 */ #endif /* __ISYS_DMA_PUBLIC_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_irq_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_irq_public.h index 736cbc4e37055..2b13688256cff 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_irq_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_irq_public.h @@ -19,7 +19,6 @@ #include "isys_irq_global.h" #include "isys_irq_local.h" -#if defined(ISP2401) void isys_irqc_state_get(const isys_irq_ID_t isys_irqc_id, isys_irqc_state_t *state); @@ -36,6 +35,5 @@ hrt_data isys_irqc_reg_load(const isys_irq_ID_t isys_irqc_id, void isys_irqc_status_enable(const isys_irq_ID_t isys_irqc_id); -#endif /* defined(ISP2401) */ #endif /* __ISYS_IRQ_PUBLIC_H__ */ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/isys_irq.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/isys_irq.h index 001c55ea970b0..952b633fdca70 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/isys_irq.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/isys_irq.h @@ -19,10 +19,8 @@ #include #include -#if defined(ISP2401) #include "isys_irq_public.h" -#endif /* defined(ISP2401) */ #endif /* __IA_CSS_ISYS_IRQ_H__ */ -- GitLab From 58e6d7d80bf1e9fc3e0b809aa343c4f445bfa493 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Thu, 13 Jul 2023 12:02:26 +0200 Subject: [PATCH 0338/1451] media: atomisp: hive_isp_css_common: Removed #if defined(ISP2401) to make driver generic Removed #if defined(ISP2401) to make code generic. Link: https://lore.kernel.org/r/20230713100231.308923-7-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/pci/hive_isp_css_common/host/input_system.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c index 7a74c679ed923..c60f0d5b01c65 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c @@ -15,7 +15,6 @@ #include "system_global.h" -#ifndef ISP2401 #include "input_system.h" #include @@ -1714,4 +1713,3 @@ static input_system_err_t input_system_multiplexer_cfg( *flags |= INPUT_SYSTEM_CFG_FLAG_SET; return INPUT_SYSTEM_ERR_NO_ERROR; } -#endif -- GitLab From 404af81df6b55cd51366c823510658236b86292b Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Thu, 13 Jul 2023 12:02:27 +0200 Subject: [PATCH 0339/1451] media: atomisp: pipeline: Removed #if defined(ISP2401) to make driver generic Removed #if defined(ISP2401) to make driver generic. Link: https://lore.kernel.org/r/20230713100231.308923-8-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h | 2 -- .../staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h b/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h index 222c381ff3b9a..5f5dab7252aad 100644 --- a/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h +++ b/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h @@ -241,7 +241,6 @@ bool ia_css_pipeline_uses_params(struct ia_css_pipeline *pipeline); */ bool ia_css_pipeline_get_sp_thread_id(unsigned int key, unsigned int *val); -#if defined(ISP2401) /** * @brief Get the pipeline io status * @@ -250,7 +249,6 @@ bool ia_css_pipeline_get_sp_thread_id(unsigned int key, unsigned int *val); * Pointer to pipe_io_status */ struct sh_css_sp_pipeline_io_status *ia_css_pipeline_get_pipe_io_status(void); -#endif /** * @brief Map an SP thread to this pipeline diff --git a/drivers/staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c b/drivers/staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c index e9e187649a657..3d8741e7d5ca7 100644 --- a/drivers/staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c +++ b/drivers/staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c @@ -454,12 +454,10 @@ bool ia_css_pipeline_has_stopped(struct ia_css_pipeline *pipeline) return sp_group.pipe[thread_id].num_stages == 0; } -#if defined(ISP2401) struct sh_css_sp_pipeline_io_status *ia_css_pipeline_get_pipe_io_status(void) { return(&sh_css_sp_group.pipe_io_status); } -#endif bool ia_css_pipeline_is_mapped(unsigned int key) { -- GitLab From f6675353feee991cf429fb22c4a8f639ec2b0ca5 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Thu, 13 Jul 2023 12:02:28 +0200 Subject: [PATCH 0340/1451] media: atomisp: ifmtr: Removed #if defined(ISP2401) to make driver generic Removed #if defined(ISP2401) to make driver generic. Link: https://lore.kernel.org/r/20230713100231.308923-9-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../atomisp/pci/hive_isp_css_common/host/input_formatter.c | 2 -- drivers/staging/media/atomisp/pci/runtime/ifmtr/src/ifmtr.c | 2 -- drivers/staging/media/atomisp/pci/sh_css_sp.c | 2 -- drivers/staging/media/atomisp/pci/sh_css_sp.h | 2 -- 4 files changed, 8 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_formatter.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_formatter.c index 5cd6136f21a21..e01f30f137a00 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_formatter.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_formatter.c @@ -15,7 +15,6 @@ #include "system_global.h" -#ifndef ISP2401 #include "input_formatter.h" #include @@ -243,4 +242,3 @@ void input_formatter_bin_get_state( HIVE_STR2MEM_EN_STAT_UPDATE_ADDRESS); return; } -#endif diff --git a/drivers/staging/media/atomisp/pci/runtime/ifmtr/src/ifmtr.c b/drivers/staging/media/atomisp/pci/runtime/ifmtr/src/ifmtr.c index 6d9f47629fbce..86254888f676a 100644 --- a/drivers/staging/media/atomisp/pci/runtime/ifmtr/src/ifmtr.c +++ b/drivers/staging/media/atomisp/pci/runtime/ifmtr/src/ifmtr.c @@ -16,7 +16,6 @@ #include "system_global.h" #include -#ifndef ISP2401 #include "ia_css_ifmtr.h" #include @@ -550,4 +549,3 @@ static int ifmtr_input_start_line( return 0; } -#endif diff --git a/drivers/staging/media/atomisp/pci/sh_css_sp.c b/drivers/staging/media/atomisp/pci/sh_css_sp.c index f35c745c22c07..eba70d4800a1e 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_sp.c +++ b/drivers/staging/media/atomisp/pci/sh_css_sp.c @@ -633,7 +633,6 @@ set_view_finder_buffer(const struct ia_css_frame *frame) return 0; } -#if !defined(ISP2401) void sh_css_sp_set_if_configs( const input_formatter_cfg_t *config_a, const input_formatter_cfg_t *config_b, @@ -655,7 +654,6 @@ void sh_css_sp_set_if_configs( return; } -#endif #if !defined(ISP2401) void diff --git a/drivers/staging/media/atomisp/pci/sh_css_sp.h b/drivers/staging/media/atomisp/pci/sh_css_sp.h index f69a79b0b0dad..b052c40e69bc0 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_sp.h +++ b/drivers/staging/media/atomisp/pci/sh_css_sp.h @@ -149,13 +149,11 @@ sh_css_sp_get_debug_state(struct sh_css_sp_debug_state *state); #endif -#if !defined(ISP2401) void sh_css_sp_set_if_configs( const input_formatter_cfg_t *config_a, const input_formatter_cfg_t *config_b, const uint8_t if_config_index); -#endif void sh_css_sp_program_input_circuit(int fmt_type, -- GitLab From feae4208b422f2ccb6496bdba6674dcdfd15a68f Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Thu, 13 Jul 2023 12:02:29 +0200 Subject: [PATCH 0341/1451] media: atomisp: Compile the object codes for a generic driver Since a generic driver should support every type of atomisp, all the codes need to be compiled. The ISP2401 flag controls the Makefile to build the binary file for ISP2400 and ISP2401. Therefore, this section of Makefile should be removed allowing all the necessary codes can be built. Moreover, some parts of "removing #ifdef ISP2401" works are related to it so they were also removed here. Link: https://lore.kernel.org/r/20230713100231.308923-10-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/Makefile | 12 ++---------- .../atomisp/pci/runtime/isys/interface/ia_css_isys.h | 9 +-------- .../pci/runtime/isys/interface/ia_css_isys_comm.h | 2 -- .../media/atomisp/pci/runtime/isys/src/csi_rx_rmgr.c | 2 -- .../atomisp/pci/runtime/isys/src/isys_dma_rmgr.c | 2 -- .../pci/runtime/isys/src/isys_stream2mmio_rmgr.c | 2 -- .../atomisp/pci/runtime/isys/src/virtual_isys.c | 2 -- 7 files changed, 3 insertions(+), 28 deletions(-) diff --git a/drivers/staging/media/atomisp/Makefile b/drivers/staging/media/atomisp/Makefile index 38b3701241098..dcf469bf1cb42 100644 --- a/drivers/staging/media/atomisp/Makefile +++ b/drivers/staging/media/atomisp/Makefile @@ -150,13 +150,8 @@ atomisp-objs += \ pci/hive_isp_css_common/host/timed_ctrl.o \ pci/hive_isp_css_common/host/vmem.o \ pci/hive_isp_css_shared/host/tag.o \ - pci/system_local.o - -# These will be needed when clean merge CHT support nicely into the driver -# Keep them here handy for when we get to that point -# - -obj-cht = \ + pci/system_local.o \ + pci/runtime/isys/src/ibuf_ctrl_rmgr.o \ pci/css_2401_system/host/csi_rx.o \ pci/css_2401_system/host/ibuf_ctrl.o \ pci/css_2401_system/host/isys_dma.o \ @@ -307,9 +302,6 @@ DEFINES := -DHRT_HW -DHRT_ISP_CSS_CUSTOM_HOST -DHRT_USE_VIR_ADDRS -D__HOST__ #DEFINES += -DUSE_KMEM_CACHE ifeq ($(CONFIG_VIDEO_ATOMISP_ISP2401),y) -atomisp-objs += \ - $(obj-cht) \ - pci/runtime/isys/src/ibuf_ctrl_rmgr.o DEFINES += -DISP2401 endif diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys.h b/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys.h index 711a321e9a3f1..d067b9fc43c79 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys.h +++ b/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys.h @@ -24,20 +24,18 @@ #include #include "ia_css_isys_comm.h" -#ifdef ISP2401 /** * Virtual Input System. (Input System 2401) */ typedef isp2401_input_system_cfg_t ia_css_isys_descr_t; /* end of Virtual Input System */ -#endif + input_system_err_t ia_css_isys_init(void); void ia_css_isys_uninit(void); enum mipi_port_id ia_css_isys_port_to_mipi_port( enum mipi_port_id api_port); -#if defined(ISP2401) /** * @brief Register one (virtual) stream. This is used to track when all @@ -74,9 +72,7 @@ int ia_css_isys_convert_compressed_format( struct isp2401_input_system_cfg_s *cfg); unsigned int ia_css_csi2_calculate_input_system_alignment( enum atomisp_input_format fmt_type); -#endif -#if !defined(ISP2401) /* CSS Receiver */ void ia_css_isys_rx_configure( const rx_cfg_t *config, @@ -93,7 +89,6 @@ void ia_css_isys_rx_clear_irq_info(enum mipi_port_id port, unsigned int irq_infos); unsigned int ia_css_isys_rx_translate_irq_infos(unsigned int bits); -#endif /* #if !defined(ISP2401) */ /* @brief Translate format and compression to format type. * @@ -111,7 +106,6 @@ int ia_css_isys_convert_stream_format_to_mipi_format( mipi_predictor_t compression, unsigned int *fmt_type); -#ifdef ISP2401 /** * Virtual Input System. (Input System 2401) */ @@ -178,6 +172,5 @@ void ia_css_isys_stream2mmio_sid_rmgr_release( stream2mmio_sid_ID_t *sid); /* end of Virtual Input System */ -#endif #endif /* __IA_CSS_ISYS_H__ */ diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys_comm.h b/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys_comm.h index d80ef42c7a642..784afc82c8d2f 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys_comm.h +++ b/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys_comm.h @@ -19,7 +19,6 @@ #include #include -#ifdef ISP2401 #include /* inline */ #include #include /* IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH */ @@ -50,5 +49,4 @@ static inline uint32_t ia_css_isys_generate_stream_id( return sp_thread_id * IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH + stream_id; } -#endif /* ISP2401*/ #endif /*_IA_CSS_ISYS_COMM_H */ diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/csi_rx_rmgr.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/csi_rx_rmgr.c index 3fc9fed1e516d..881036c67baf6 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/csi_rx_rmgr.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/csi_rx_rmgr.c @@ -15,7 +15,6 @@ #include "system_global.h" -#ifdef ISP2401 #include "assert_support.h" #include "platform_support.h" @@ -165,4 +164,3 @@ int ia_css_isys_csi_rx_unregister_stream( } return retval; } -#endif diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_dma_rmgr.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_dma_rmgr.c index 261c6460e9705..4df0a9188ee66 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_dma_rmgr.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_dma_rmgr.c @@ -15,7 +15,6 @@ #include "system_global.h" -#ifdef ISP2401 #include "assert_support.h" #include "platform_support.h" @@ -85,4 +84,3 @@ void ia_css_isys_dma_channel_rmgr_release( } } } -#endif diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_stream2mmio_rmgr.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_stream2mmio_rmgr.c index fb0cb183f7017..b6be63746c3ee 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_stream2mmio_rmgr.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_stream2mmio_rmgr.c @@ -15,7 +15,6 @@ #include "system_global.h" -#ifdef ISP2401 #include "assert_support.h" #include "platform_support.h" @@ -87,4 +86,3 @@ void ia_css_isys_stream2mmio_sid_rmgr_release( } } } -#endif diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c index def8a0b1d2ec1..269a811905778 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c @@ -17,7 +17,6 @@ #include "system_global.h" -#ifdef ISP2401 #include "ia_css_isys.h" #include "ia_css_debug.h" @@ -866,4 +865,3 @@ static csi_mipi_packet_type_t get_csi_mipi_packet_type( } /* end of Private Methods */ -#endif -- GitLab From 0df4319c55cb5722a9bea9e4ca0ca849c1d9c524 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Thu, 13 Jul 2023 12:02:30 +0200 Subject: [PATCH 0342/1451] media: atomisp: rx: Removed #if defined(ISP2401) to make driver generic The conflicts of variable declarations were resolved through previous commits so the #if defined(ISP2401) can be removed. Link: https://lore.kernel.org/r/20230713100231.308923-11-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/pci/runtime/isys/src/rx.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c index b58f4fd4a35c9..c8316e0965d06 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c @@ -20,7 +20,6 @@ #include "ia_css_irq.h" #include "sh_css_internal.h" -#if !defined(ISP2401) void ia_css_isys_rx_enable_all_interrupts(enum mipi_port_id port) { hrt_data bits = receiver_port_reg_load(RX0_ID, @@ -209,9 +208,7 @@ void ia_css_isys_rx_clear_irq_info(enum mipi_port_id port, return; } -#endif /* #if !defined(ISP2401) */ -#if !defined(ISP2401) static int ia_css_isys_2400_set_fmt_type(enum atomisp_input_format input_format, unsigned int *fmt_type) { @@ -283,9 +280,7 @@ static int ia_css_isys_2400_set_fmt_type(enum atomisp_input_format input_format, } return 0; } -#endif /* #ifndef ISP2401 */ -#if defined(ISP2401) static int ia_css_isys_2401_set_fmt_type(enum atomisp_input_format input_format, unsigned int *fmt_type) { @@ -373,7 +368,6 @@ static int ia_css_isys_2401_set_fmt_type(enum atomisp_input_format input_format, } return 0; } -#endif /* #ifdef ISP2401 */ int ia_css_isys_convert_stream_format_to_mipi_format( enum atomisp_input_format input_format, @@ -423,14 +417,12 @@ int ia_css_isys_convert_stream_format_to_mipi_format( * * MW: For some reason the mapping is not 1-to-1 */ -#if defined(ISP2401) - return ia_css_isys_2401_set_fmt_type(input_format, fmt_type); -#else - return ia_css_isys_2400_set_fmt_type(input_format, fmt_type); -#endif + if (IS_ISP2401) + return ia_css_isys_2401_set_fmt_type(input_format, fmt_type); + else + return ia_css_isys_2400_set_fmt_type(input_format, fmt_type); } -#if defined(ISP2401) static mipi_predictor_t sh_css_csi2_compression_type_2_mipi_predictor( enum ia_css_csi2_compression_type type) { @@ -547,9 +539,7 @@ unsigned int ia_css_csi2_calculate_input_system_alignment( return memory_alignment_in_bytes; } -#endif -#if !defined(ISP2401) static const mipi_lane_cfg_t MIPI_PORT_LANES[N_RX_MODE][N_MIPI_PORT_ID] = { {MIPI_4LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, {MIPI_3LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, @@ -671,4 +661,3 @@ void ia_css_isys_rx_disable(void) } return; } -#endif /* if !defined(ISP2401) */ -- GitLab From 16fb1d5b2bbea609bbdfa832fd99771a744aff78 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Thu, 13 Jul 2023 12:02:31 +0200 Subject: [PATCH 0343/1451] media: atomisp: isys_init: Initiate atomisp in a generic manner The original implementation distinguishes and initiates atomisp during compiler time. This commit allows isys_init to initiate isys for both types of atomisp in a generic manner. Link: https://lore.kernel.org/r/20230713100231.308923-12-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../atomisp/pci/runtime/isys/src/isys_init.c | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_init.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_init.c index d0a43c44963cd..1a7b45bb45446 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_init.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_init.c @@ -18,13 +18,10 @@ #include "ia_css_isys.h" #include "platform_support.h" -#ifdef ISP2401 #include "isys_dma_public.h" /* isys2401_dma_set_max_burst_size() */ #include "isys_irq.h" -#endif -#if !defined(ISP2401) -input_system_err_t ia_css_isys_init(void) +input_system_err_t ia_css_isys_2400_init(void) { backend_channel_cfg_t backend_ch0; backend_channel_cfg_t backend_ch1; @@ -86,8 +83,8 @@ input_system_err_t ia_css_isys_init(void) return error; } -#elif defined(ISP2401) -input_system_err_t ia_css_isys_init(void) + +input_system_err_t ia_css_isys_2401_init(void) { ia_css_isys_csi_rx_lut_rmgr_init(); ia_css_isys_ibuf_rmgr_init(); @@ -104,19 +101,21 @@ input_system_err_t ia_css_isys_init(void) return INPUT_SYSTEM_ERR_NO_ERROR; } -#endif -#if !defined(ISP2401) -void ia_css_isys_uninit(void) +input_system_err_t ia_css_isys_init(void) { + if (IS_ISP2401) + return ia_css_isys_2401_init(); + + return ia_css_isys_2400_init(); } -#elif defined(ISP2401) + void ia_css_isys_uninit(void) { - ia_css_isys_csi_rx_lut_rmgr_uninit(); - ia_css_isys_ibuf_rmgr_uninit(); - ia_css_isys_dma_channel_rmgr_uninit(); - ia_css_isys_stream2mmio_sid_rmgr_uninit(); + if (IS_ISP2401) { + ia_css_isys_csi_rx_lut_rmgr_uninit(); + ia_css_isys_ibuf_rmgr_uninit(); + ia_css_isys_dma_channel_rmgr_uninit(); + ia_css_isys_stream2mmio_sid_rmgr_uninit(); + } } -#endif - -- GitLab From b70fbcd6507ccb31b469214e11e8a37a8ea426b4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 15 Jul 2023 19:09:04 +0200 Subject: [PATCH 0344/1451] media: atomisp: Remove empty isys_public.h isys_public.h is empty, remove it. Link: https://lore.kernel.org/r/20230715170906.3627-1-hdegoede@redhat.com Signed-off-by: Hans de Goede Reviewed-by: Kate Hsuan Signed-off-by: Mauro Carvalho Chehab --- .../hive_isp_css_include/host/isys_public.h | 19 ------------------- .../atomisp/pci/isp2400_input_system_public.h | 1 - 2 files changed, 20 deletions(-) delete mode 100644 drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_public.h diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_public.h deleted file mode 100644 index 9dacef7a5cc1f..0000000000000 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_public.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * 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. - */ - -#ifndef __ISYS_PUBLIC_H_INCLUDED__ -#define __ISYS_PUBLIC_H_INCLUDED__ - -#endif /* __ISYS_PUBLIC_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h index 375c0db84b557..b1360eeb58df8 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h @@ -17,7 +17,6 @@ #define __INPUT_SYSTEM_2400_PUBLIC_H_INCLUDED__ #include -#include "isys_public.h" typedef struct receiver_state_s receiver_state_t; -- GitLab From 983993cb8231993c1ecd10dab0dbe0ff2852d8fa Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 15 Jul 2023 19:09:05 +0200 Subject: [PATCH 0345/1451] media: atomisp: Remove aliases for MIPI_FORMAT_2400_CUSTOM0 isp2400_input_system_local.h defines 2 aliases for MIPI_FORMAT_2400_CUSTOM0 MIPI_FORMAT_JPEG, which is entirely unused and MIPI_FORMAT_BINARY_8 which is used once in ia_css_isys_2400_set_fmt_type(). Drop these aliases and directly use MIPI_FORMAT_2400_CUSTOM0 in ia_css_isys_2400_set_fmt_type(). Link: https://lore.kernel.org/r/20230715170906.3627-2-hdegoede@redhat.com Signed-off-by: Hans de Goede Reviewed-by: Kate Hsuan Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/isp2400_input_system_local.h | 2 -- drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h index e7b84fdbb4e03..6319d6449f201 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h @@ -200,8 +200,6 @@ typedef enum { N_MIPI_FORMAT_2400, } mipi_format_2400_t; -#define MIPI_FORMAT_JPEG MIPI_FORMAT_2400_CUSTOM0 -#define MIPI_FORMAT_BINARY_8 MIPI_FORMAT_2400_CUSTOM0 #define N_MIPI_FORMAT_CUSTOM 8 /* The number of stores for compressed format types */ diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c index c8316e0965d06..deb4130f710cd 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c @@ -271,7 +271,7 @@ static int ia_css_isys_2400_set_fmt_type(enum atomisp_input_format input_format, *fmt_type = MIPI_FORMAT_2400_RAW16; break; case ATOMISP_INPUT_FORMAT_BINARY_8: - *fmt_type = MIPI_FORMAT_BINARY_8; + *fmt_type = MIPI_FORMAT_2400_CUSTOM0; break; case ATOMISP_INPUT_FORMAT_YUV420_16: case ATOMISP_INPUT_FORMAT_YUV422_16: -- GitLab From b6e5978323d5aca0b64f02efbca5f735c114eeb0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 15 Jul 2023 19:09:06 +0200 Subject: [PATCH 0346/1451] media: atomisp: Mark ia_css_isys_240?_init() static ia_css_isys_240?_init() are only used inside the C file where they are declared, mark them as static fixing: drivers/staging/media/atomisp/pci/runtime/isys/src/isys_init.c:24:20: warning: no previous prototype for 'ia_css_isys_2400_init' 24 | input_system_err_t ia_css_isys_2400_init(void) | ^~~~~~~~~~~~~~~~~~~~~ drivers/staging/media/atomisp/pci/runtime/isys/src/isys_init.c:87:20: warning: no previous prototype for 'ia_css_isys_2401_init' 87 | input_system_err_t ia_css_isys_2401_init(void) | ^~~~~~~~~~~~~~~~~~~~~ Closes: https://lore.kernel.org/oe-kbuild-all/202307152046.rvhFGrbz-lkp@intel.com/ Link: https://lore.kernel.org/r/20230715170906.3627-3-hdegoede@redhat.com Reported-by: kernel test robot Signed-off-by: Hans de Goede Reviewed-by: Kate Hsuan Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/atomisp/pci/runtime/isys/src/isys_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_init.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_init.c index 1a7b45bb45446..18bfe10109892 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_init.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_init.c @@ -21,7 +21,7 @@ #include "isys_dma_public.h" /* isys2401_dma_set_max_burst_size() */ #include "isys_irq.h" -input_system_err_t ia_css_isys_2400_init(void) +static input_system_err_t ia_css_isys_2400_init(void) { backend_channel_cfg_t backend_ch0; backend_channel_cfg_t backend_ch1; @@ -84,7 +84,7 @@ input_system_err_t ia_css_isys_2400_init(void) return error; } -input_system_err_t ia_css_isys_2401_init(void) +static input_system_err_t ia_css_isys_2401_init(void) { ia_css_isys_csi_rx_lut_rmgr_init(); ia_css_isys_ibuf_rmgr_init(); -- GitLab From 68b9a816cabefc9c9f04c7b99ad2d92cb306136b Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Wed, 2 Aug 2023 11:55:55 +0200 Subject: [PATCH 0347/1451] media: atomisp: ia_css_raw.host: Remove #ifdef ISP2401 to make the driver generic Remove #ifdef from the code and made the code generic. The raw image configuration was determined during runtime. Link: https://lore.kernel.org/r/20230802095606.1298152-2-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../isp/kernels/raw/raw_1.0/ia_css_raw.host.c | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/raw/raw_1.0/ia_css_raw.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/raw/raw_1.0/ia_css_raw.host.c index 646d6e39c1e58..40d4a05215627 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/raw/raw_1.0/ia_css_raw.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/raw/raw_1.0/ia_css_raw.host.c @@ -73,17 +73,9 @@ int ia_css_raw_config(struct sh_css_isp_raw_isp_config *to, const struct ia_css_frame_info *internal_info = from->internal_info; int ret; -#if !defined(ISP2401) - /* 2401 input system uses input width width */ - in_info = internal_info; -#else - /*in some cases, in_info is NULL*/ - if (in_info) - (void)internal_info; - else + if (!IS_ISP2401 || !in_info) in_info = internal_info; -#endif ret = ia_css_dma_configure_from_info(&to->port_b, in_info); if (ret) return ret; @@ -99,11 +91,12 @@ int ia_css_raw_config(struct sh_css_isp_raw_isp_config *to, to->two_ppc = from->two_ppc; to->stream_format = css2isp_stream_format(from->stream_format); to->deinterleaved = from->deinterleaved; -#if defined(ISP2401) - to->start_column = in_info->crop_info.start_column; - to->start_line = in_info->crop_info.start_line; - to->enable_left_padding = from->enable_left_padding; -#endif + + if (IS_ISP2401) { + to->start_column = in_info->crop_info.start_column; + to->start_line = in_info->crop_info.start_line; + to->enable_left_padding = from->enable_left_padding; + } return 0; } -- GitLab From 2b5d1e149edf31d54bd93417bf81c960a96019b3 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Wed, 2 Aug 2023 11:55:56 +0200 Subject: [PATCH 0348/1451] media: atomisp: binary: Removed #ifdef ISP2401 to make driver generic Removed #ifdef ISP2401 to make the driver generic. The driver flow is determined in runtime. Link: https://lore.kernel.org/r/20230802095606.1298152-3-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/pci/runtime/binary/src/binary.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c b/drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c index 768da86b8c2c1..0f3729e55e14a 100644 --- a/drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c +++ b/drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c @@ -604,13 +604,14 @@ binary_in_frame_padded_width(int in_frame_width, int rval; int nr_of_left_paddings; /* number of paddings pixels on the left of an image line */ -#if defined(ISP2401) - /* the output image line of Input System 2401 does not have the left paddings */ - nr_of_left_paddings = 0; -#else - /* in other cases, the left padding pixels are always 128 */ - nr_of_left_paddings = 2 * ISP_VEC_NELEMS; -#endif + if (IS_ISP2401) { + /* the output image line of Input System 2401 does not have the left paddings */ + nr_of_left_paddings = 0; + } else { + /* in other cases, the left padding pixels are always 128 */ + nr_of_left_paddings = 2 * ISP_VEC_NELEMS; + } + if (need_scaling) { /* In SDV use-case, we need to match left-padding of * primary and the video binary. */ -- GitLab From 7d5901b49c22b55c48a91c545f8c94f0bbbcbf9a Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Wed, 2 Aug 2023 11:55:57 +0200 Subject: [PATCH 0349/1451] media: atomisp: hive_isp_css_include: Removed #ifdef ISP2401 to make driver generic Removed #ifdef ISP2401 to make the driver generic. Link: https://lore.kernel.org/r/20230802095606.1298152-4-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/pci/hive_isp_css_include/host/csi_rx_public.h | 2 -- .../atomisp/pci/hive_isp_css_include/host/pixelgen_public.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/csi_rx_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/csi_rx_public.h index 3d6621f2fa96c..693154e8ec2f9 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/csi_rx_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/csi_rx_public.h @@ -16,7 +16,6 @@ #ifndef __CSI_RX_PUBLIC_H_INCLUDED__ #define __CSI_RX_PUBLIC_H_INCLUDED__ -#ifdef ISP2401 /***************************************************** * * Native command interface (NCI). @@ -132,5 +131,4 @@ void csi_rx_be_ctrl_reg_store( const hrt_address reg, const hrt_data value); /* end of DLI */ -#endif /* ISP2401 */ #endif /* __CSI_RX_PUBLIC_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/pixelgen_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/pixelgen_public.h index 40a9fb6d77618..da10e6b98c63f 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/pixelgen_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/pixelgen_public.h @@ -16,7 +16,6 @@ #ifndef __PIXELGEN_PUBLIC_H_INCLUDED__ #define __PIXELGEN_PUBLIC_H_INCLUDED__ -#ifdef ISP2401 /***************************************************** * * Native command interface (NCI). @@ -76,5 +75,4 @@ STORAGE_CLASS_PIXELGEN_H void pixelgen_ctrl_reg_store( const hrt_data value); /* end of DLI */ -#endif /* ISP2401 */ #endif /* __PIXELGEN_PUBLIC_H_INCLUDED__ */ -- GitLab From fdd9681f7e9ede01f53241326a7ab259de4762cc Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Wed, 2 Aug 2023 11:55:58 +0200 Subject: [PATCH 0350/1451] media: atomisp: atomisp_compat_css20: Removed #ifdef ISP2401 to make driver generic Removed #ifdef ISP2401 to make code to be generic. The driver flow is determined in runtime. Link: https://lore.kernel.org/r/20230802095606.1298152-5-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/pci/atomisp_compat_css20.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c index 0c02f41e1a1f8..02f06294bbfe0 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c +++ b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c @@ -849,19 +849,17 @@ int atomisp_css_irq_translate(struct atomisp_device *isp, void atomisp_css_rx_get_irq_info(enum mipi_port_id port, unsigned int *infos) { -#ifndef ISP2401 - ia_css_isys_rx_get_irq_info(port, infos); -#else - *infos = 0; -#endif + if (IS_ISP2401) + *infos = 0; + else + ia_css_isys_rx_get_irq_info(port, infos); } void atomisp_css_rx_clear_irq_info(enum mipi_port_id port, unsigned int infos) { -#ifndef ISP2401 - ia_css_isys_rx_clear_irq_info(port, infos); -#endif + if (!IS_ISP2401) + ia_css_isys_rx_clear_irq_info(port, infos); } int atomisp_css_irq_enable(struct atomisp_device *isp, -- GitLab From fc280df3aa3738865bff77dfb0fafc249ac87954 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Wed, 2 Aug 2023 11:55:59 +0200 Subject: [PATCH 0351/1451] media: atomisp: sh_css_mipi: Removed unused code ia_css_mipi_frame_enable_check_on_size() ia_css_mipi_frame_enable_check_on_size() wasn't used by any functions. So, it can be removed. Link: https://lore.kernel.org/r/20230802095606.1298152-6-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/atomisp/pci/ia_css_mipi.h | 16 ---------- .../staging/media/atomisp/pci/sh_css_mipi.c | 29 ------------------- 2 files changed, 45 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/ia_css_mipi.h b/drivers/staging/media/atomisp/pci/ia_css_mipi.h index 9e50e1c619be2..cd6e0111d9f4e 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_mipi.h +++ b/drivers/staging/media/atomisp/pci/ia_css_mipi.h @@ -25,22 +25,6 @@ #include "ia_css_stream_format.h" #include "ia_css_input_port.h" -/* @brief Register size of a CSS MIPI frame for check during capturing. - * - * @param[in] port CSI-2 port this check is registered. - * @param[in] size_mem_words The frame size in memory words (32B). - * @return Return the error in case of failure. E.g. MAX_NOF_ENTRIES REACHED - * - * Register size of a CSS MIPI frame to check during capturing. Up to - * IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES entries per port allowed. Entries are reset - * when stream is stopped. - * - * - */ -int -ia_css_mipi_frame_enable_check_on_size(const enum mipi_port_id port, - const unsigned int size_mem_words); - /* @brief Calculate the size of a mipi frame. * * @param[in] width The width (in pixels) of the frame. diff --git a/drivers/staging/media/atomisp/pci/sh_css_mipi.c b/drivers/staging/media/atomisp/pci/sh_css_mipi.c index ced21dedf7ac9..b7c1e164ee244 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_mipi.c +++ b/drivers/staging/media/atomisp/pci/sh_css_mipi.c @@ -185,35 +185,6 @@ ia_css_mipi_frame_calculate_size(const unsigned int width, return err; } -/* - * Check if a source port or TPG/PRBS ID is valid - */ - -#if !defined(ISP2401) -int -ia_css_mipi_frame_enable_check_on_size(const enum mipi_port_id port, - const unsigned int size_mem_words) -{ - u32 idx; - - int err = -EBUSY; - - OP___assert(port < N_CSI_PORTS); - OP___assert(size_mem_words != 0); - - for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT && - my_css.mipi_sizes_for_check[port][idx] != 0; - idx++) { /* do nothing */ - } - if (idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT) { - my_css.mipi_sizes_for_check[port][idx] = size_mem_words; - err = 0; - } - - return err; -} -#endif - void mipi_init(void) { -- GitLab From 1e1ea859e4e6c2346be1513c006447a62717133a Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Wed, 2 Aug 2023 11:56:00 +0200 Subject: [PATCH 0352/1451] media: atomisp: sh_css: Removed #ifdef ISP2401 to make the driver generic Removed #ifdef ISP2401 to expose the necessary functions for ISP2401 and also make the driver generic. Link: https://lore.kernel.org/r/20230802095606.1298152-7-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index 67c581d3c1a63..8b5fb3703d592 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -2957,7 +2957,6 @@ init_vf_frameinfo_defaults(struct ia_css_pipe *pipe, return err; } -#ifdef ISP2401 static unsigned int get_crop_lines_for_bayer_order(const struct ia_css_stream_config *config) { @@ -3059,11 +3058,11 @@ ia_css_get_crop_offsets( pipe->config.input_effective_res.height); input_res = &pipe->stream->config.input_config.input_res; -#ifndef ISP2401 - effective_res = &pipe->stream->config.input_config.effective_res; -#else - effective_res = &pipe->config.input_effective_res; -#endif + + if (IS_ISP2401) + effective_res = &pipe->config.input_effective_res; + else + effective_res = &pipe->stream->config.input_config.effective_res; get_pipe_extra_pixel(pipe, &extra_row, &extra_col); @@ -3101,7 +3100,6 @@ ia_css_get_crop_offsets( return; } -#endif static int init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe, -- GitLab From d1f3bed602239c62a2374c518a9e19c7dc75f66e Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Wed, 2 Aug 2023 11:56:01 +0200 Subject: [PATCH 0353/1451] media: atomisp: sh_css_sp: Remove #ifdef ISP2401 to make driver generic Removed #ifdef ISP2401 to make the driver generic. The uncessary codes were removed and the types of the ISP is determines in runtime. Link: https://lore.kernel.org/r/20230802095606.1298152-8-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css_sp.c | 60 +++++++------------ drivers/staging/media/atomisp/pci/sh_css_sp.h | 2 - 2 files changed, 21 insertions(+), 41 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css_sp.c b/drivers/staging/media/atomisp/pci/sh_css_sp.c index eba70d4800a1e..cd7f5a3fecaa6 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_sp.c +++ b/drivers/staging/media/atomisp/pci/sh_css_sp.c @@ -17,9 +17,7 @@ #include "sh_css_sp.h" -#if !defined(ISP2401) #include "input_formatter.h" -#endif #include "dma.h" /* N_DMA_CHANNEL_ID */ @@ -228,11 +226,8 @@ sh_css_sp_start_binary_copy(unsigned int pipe_num, IA_CSS_LOG("pipe_id %d port_config %08x", pipe->pipe_id, pipe->inout_port_config); -#if !defined(ISP2401) - sh_css_sp_group.config.input_formatter.isp_2ppc = (uint8_t)two_ppc; -#else - (void)two_ppc; -#endif + if (!IS_ISP2401) + sh_css_sp_group.config.input_formatter.isp_2ppc = (uint8_t)two_ppc; sh_css_sp_stage.num = stage_num; sh_css_sp_stage.stage_type = SH_CSS_SP_STAGE_TYPE; @@ -306,11 +301,8 @@ sh_css_sp_start_raw_copy(struct ia_css_frame *out_frame, IA_CSS_LOG("pipe_id %d port_config %08x", pipe->pipe_id, pipe->inout_port_config); -#if !defined(ISP2401) - sh_css_sp_group.config.input_formatter.isp_2ppc = (uint8_t)two_ppc; -#else - (void)two_ppc; -#endif + if (!IS_ISP2401) + sh_css_sp_group.config.input_formatter.isp_2ppc = (uint8_t)two_ppc; sh_css_sp_stage.num = stage_num; sh_css_sp_stage.xmem_bin_addr = 0x0; @@ -655,7 +647,6 @@ void sh_css_sp_set_if_configs( return; } -#if !defined(ISP2401) void sh_css_sp_program_input_circuit(int fmt_type, int ch_id, @@ -672,9 +663,7 @@ sh_css_sp_program_input_circuit(int fmt_type, sh_css_sp_group.config.input_circuit_cfg_changed = true; sh_css_sp_stage.program_input_circuit = true; } -#endif -#if !defined(ISP2401) void sh_css_sp_configure_sync_gen(int width, int height, int hblank_cycles, @@ -705,7 +694,6 @@ sh_css_sp_configure_prbs(int seed) { sh_css_sp_group.config.prbs.seed = seed; } -#endif void sh_css_sp_configure_enable_raw_pool_locking(bool lock_all) @@ -755,22 +743,18 @@ sh_css_sp_init_group(bool two_ppc, bool no_isp_sync, uint8_t if_config_index) { -#if !defined(ISP2401) - sh_css_sp_group.config.input_formatter.isp_2ppc = two_ppc; -#else - (void)two_ppc; -#endif + if (!IS_ISP2401) + sh_css_sp_group.config.input_formatter.isp_2ppc = two_ppc; sh_css_sp_group.config.no_isp_sync = (uint8_t)no_isp_sync; /* decide whether the frame is processed online or offline */ if (if_config_index == SH_CSS_IF_CONFIG_NOT_NEEDED) return; -#if !defined(ISP2401) - assert(if_config_index < SH_CSS_MAX_IF_CONFIGS); - sh_css_sp_group.config.input_formatter.set[if_config_index].stream_format = - input_format; -#else - (void)input_format; -#endif + + if (!IS_ISP2401) { + assert(if_config_index < SH_CSS_MAX_IF_CONFIGS); + sh_css_sp_group.config.input_formatter.set[if_config_index].stream_format = + input_format; + } } void @@ -1029,18 +1013,16 @@ sh_css_sp_init_stage(struct ia_css_binary *binary, if (err) return err; -#ifdef ISP2401 - pipe = find_pipe_by_num(sh_css_sp_group.pipe[thread_id].pipe_num); - if (!pipe) - return -EINVAL; + if (IS_ISP2401) { + pipe = find_pipe_by_num(sh_css_sp_group.pipe[thread_id].pipe_num); + if (!pipe) + return -EINVAL; - if (args->in_frame) - ia_css_get_crop_offsets(pipe, &args->in_frame->frame_info); - else - ia_css_get_crop_offsets(pipe, &binary->in_frame_info); -#else - (void)pipe; /*avoid build warning*/ -#endif + if (args->in_frame) + ia_css_get_crop_offsets(pipe, &args->in_frame->frame_info); + else + ia_css_get_crop_offsets(pipe, &binary->in_frame_info); + } err = configure_isp_from_args(&sh_css_sp_group.pipe[thread_id], binary, args, two_ppc, sh_css_sp_stage.deinterleaved); diff --git a/drivers/staging/media/atomisp/pci/sh_css_sp.h b/drivers/staging/media/atomisp/pci/sh_css_sp.h index b052c40e69bc0..36b693bd916a5 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_sp.h +++ b/drivers/staging/media/atomisp/pci/sh_css_sp.h @@ -18,9 +18,7 @@ #include #include -#if !defined(ISP2401) #include "input_formatter.h" -#endif #include "ia_css_binary.h" #include "ia_css_types.h" -- GitLab From ade6b4c2b8a33866af5760beeea3b5ca2c9097de Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Wed, 2 Aug 2023 11:56:02 +0200 Subject: [PATCH 0354/1451] media: atomisp: sh_css: Removed #ifdef ISP2401 to make driver generic Removed #ifdef ISP2401 to expose ia_css_stream_configure_rx() for ISP2400. Link: https://lore.kernel.org/r/20230802095606.1298152-9-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css.c | 54 +++++++++------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index 8b5fb3703d592..e2e608d4c8a5b 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -56,9 +56,7 @@ #include "assert_support.h" #include "math_support.h" #include "sw_event_global.h" /* Event IDs.*/ -#if !defined(ISP2401) #include "ia_css_ifmtr.h" -#endif #include "input_system.h" #include "mmu_device.h" /* mmu_set_page_table_base_index(), ... */ #include "ia_css_mmu_private.h" /* sh_css_mmu_set_page_table_base_index() */ @@ -345,7 +343,6 @@ static struct sh_css_hmm_buffer_record *sh_css_hmm_buffer_record_validate(ia_css_ptr ddr_buffer_addr, enum ia_css_buffer_type type); -#ifdef ISP2401 static unsigned int get_crop_lines_for_bayer_order(const struct ia_css_stream_config *config); static unsigned int get_crop_columns_for_bayer_order(const struct @@ -353,8 +350,6 @@ static unsigned int get_crop_columns_for_bayer_order(const struct static void get_pipe_extra_pixel(struct ia_css_pipe *pipe, unsigned int *extra_row, unsigned int *extra_column); -#endif - static void sh_css_pipe_free_shading_table(struct ia_css_pipe *pipe) { @@ -7971,7 +7966,6 @@ ia_css_pipe_override_frame_format(struct ia_css_pipe *pipe, return err; } -#if !defined(ISP2401) /* Configuration of INPUT_SYSTEM_VERSION_2401 is done on SP */ static int ia_css_stream_configure_rx(struct ia_css_stream *stream) @@ -8014,7 +8008,6 @@ ia_css_stream_configure_rx(struct ia_css_stream *stream) stream->reconfigure_css_rx = true; return 0; } -#endif static struct ia_css_pipe * find_pipe(struct ia_css_pipe *pipes[], unsigned int num_pipes, @@ -8100,9 +8093,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, /* check if mipi size specified */ if (stream_config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) -#ifdef ISP2401 - if (!stream_config->online) -#endif + if (!IS_ISP2401 || (IS_ISP2401 && !stream_config->online)) { unsigned int port = (unsigned int)stream_config->source.port.port; @@ -8203,32 +8194,31 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, switch (curr_stream->config.mode) { case IA_CSS_INPUT_MODE_SENSOR: case IA_CSS_INPUT_MODE_BUFFERED_SENSOR: -#if !defined(ISP2401) - ia_css_stream_configure_rx(curr_stream); -#endif + if (!IS_ISP2401) + ia_css_stream_configure_rx(curr_stream); break; case IA_CSS_INPUT_MODE_TPG: -#if !defined(ISP2401) - IA_CSS_LOG("tpg_configuration: x_mask=%d, y_mask=%d, x_delta=%d, y_delta=%d, xy_mask=%d", - curr_stream->config.source.tpg.x_mask, - curr_stream->config.source.tpg.y_mask, - curr_stream->config.source.tpg.x_delta, - curr_stream->config.source.tpg.y_delta, - curr_stream->config.source.tpg.xy_mask); - - sh_css_sp_configure_tpg( - curr_stream->config.source.tpg.x_mask, - curr_stream->config.source.tpg.y_mask, - curr_stream->config.source.tpg.x_delta, - curr_stream->config.source.tpg.y_delta, - curr_stream->config.source.tpg.xy_mask); -#endif + if (!IS_ISP2401) { + IA_CSS_LOG("tpg_configuration: x_mask=%d, y_mask=%d, x_delta=%d, y_delta=%d, xy_mask=%d", + curr_stream->config.source.tpg.x_mask, + curr_stream->config.source.tpg.y_mask, + curr_stream->config.source.tpg.x_delta, + curr_stream->config.source.tpg.y_delta, + curr_stream->config.source.tpg.xy_mask); + + sh_css_sp_configure_tpg( + curr_stream->config.source.tpg.x_mask, + curr_stream->config.source.tpg.y_mask, + curr_stream->config.source.tpg.x_delta, + curr_stream->config.source.tpg.y_delta, + curr_stream->config.source.tpg.xy_mask); + } break; case IA_CSS_INPUT_MODE_PRBS: -#if !defined(ISP2401) - IA_CSS_LOG("mode prbs"); - sh_css_sp_configure_prbs(curr_stream->config.source.prbs.seed); -#endif + if (!IS_ISP2401) { + IA_CSS_LOG("mode prbs"); + sh_css_sp_configure_prbs(curr_stream->config.source.prbs.seed); + } break; case IA_CSS_INPUT_MODE_MEMORY: IA_CSS_LOG("mode memory"); -- GitLab From ad6979477073bfef6fb95f33dfd0a9bce49e6007 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Wed, 2 Aug 2023 11:56:03 +0200 Subject: [PATCH 0355/1451] media: atomisp: sh_css: Renamed sh_css_config_input_network() sh_css_config_input_network() is renamed to sh_css_config_input_network_2400() and sh_css_config_input_network_2401() since a generic driver should cover the implementation for both types. Link: https://lore.kernel.org/r/20230802095606.1298152-10-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css.c | 52 +++++++++------------- 1 file changed, 21 insertions(+), 31 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index e2e608d4c8a5b..94cb48fa59a2f 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -467,9 +467,8 @@ ia_css_stream_input_format_bits_per_pixel(struct ia_css_stream *stream) /* TODO: move define to proper file in tools */ #define GP_ISEL_TPG_MODE 0x90058 -#if !defined(ISP2401) static int -sh_css_config_input_network(struct ia_css_stream *stream) +sh_css_config_input_network_2400(struct ia_css_stream *stream) { unsigned int fmt_type; struct ia_css_pipe *pipe = stream->last_pipe; @@ -523,7 +522,7 @@ sh_css_config_input_network(struct ia_css_stream *stream) "sh_css_config_input_network() leave:\n"); return 0; } -#elif defined(ISP2401) + static unsigned int csi2_protocol_calculate_max_subpixels_per_line( enum atomisp_input_format format, unsigned int pixels_per_line) @@ -819,9 +818,10 @@ static bool sh_css_translate_stream_cfg_to_input_system_input_port_attr( stream_cfg->source.port.num_lanes; isys_stream_descr->csi_port_attr.fmt_type = fmt_type; isys_stream_descr->csi_port_attr.ch_id = stream_cfg->channel_id; -#ifdef ISP2401 - isys_stream_descr->online = stream_cfg->online; -#endif + + if (IS_ISP2401) + isys_stream_descr->online = stream_cfg->online; + err |= ia_css_isys_convert_compressed_format( &stream_cfg->source.port.compression, isys_stream_descr); @@ -844,15 +844,15 @@ static bool sh_css_translate_stream_cfg_to_input_system_input_port_attr( stream_cfg->metadata_config.resolution.width; isys_stream_descr->metadata.lines_per_frame = stream_cfg->metadata_config.resolution.height; -#ifdef ISP2401 + /* * For new input system, number of str2mmio requests must be even. * So we round up number of metadata lines to be even. */ - if (isys_stream_descr->metadata.lines_per_frame > 0) + if (IS_ISP2401 && isys_stream_descr->metadata.lines_per_frame > 0) isys_stream_descr->metadata.lines_per_frame += (isys_stream_descr->metadata.lines_per_frame & 1); -#endif + isys_stream_descr->metadata.align_req_in_bytes = ia_css_csi2_calculate_input_system_alignment( stream_cfg->metadata_config.data_type); @@ -967,7 +967,7 @@ static bool sh_css_translate_binary_info_to_input_system_output_port_attr( } static int -sh_css_config_input_network(struct ia_css_stream *stream) +sh_css_config_input_network_2401(struct ia_css_stream *stream) { bool rc; ia_css_isys_descr_t isys_stream_descr; @@ -1176,7 +1176,6 @@ static inline int stream_unregister_with_csi_rx( { return stream_csi_rx_helper(stream, ia_css_isys_csi_rx_unregister_stream); } -#endif static void @@ -1189,14 +1188,11 @@ start_binary(struct ia_css_pipe *pipe, if (binary) sh_css_metrics_start_binary(&binary->metrics); - -#if !defined(ISP2401) - if (pipe->stream->reconfigure_css_rx) { + if (!IS_ISP2401 && pipe->stream->reconfigure_css_rx) { ia_css_isys_rx_configure(&pipe->stream->csi_rx_config, pipe->stream->config.mode); pipe->stream->reconfigure_css_rx = false; } -#endif } /* start the copy function on the SP */ @@ -1209,22 +1205,18 @@ start_copy_on_sp(struct ia_css_pipe *pipe, if ((!pipe) || (!pipe->stream)) return -EINVAL; -#if !defined(ISP2401) - if (pipe->stream->reconfigure_css_rx) + if (!IS_ISP2401 && pipe->stream->reconfigure_css_rx) ia_css_isys_rx_disable(); -#endif if (pipe->stream->config.input_config.format != ATOMISP_INPUT_FORMAT_BINARY_8) return -EINVAL; sh_css_sp_start_binary_copy(ia_css_pipe_get_pipe_num(pipe), out_frame, pipe->stream->config.pixels_per_clock == 2); -#if !defined(ISP2401) - if (pipe->stream->reconfigure_css_rx) { + if (!IS_ISP2401 && pipe->stream->reconfigure_css_rx) { ia_css_isys_rx_configure(&pipe->stream->csi_rx_config, pipe->stream->config.mode); pipe->stream->reconfigure_css_rx = false; } -#endif return 0; } @@ -4466,7 +4458,6 @@ ia_css_stream_get_buffer_depth(struct ia_css_stream *stream, return 0; } -#if !defined(ISP2401) unsigned int sh_css_get_mipi_sizes_for_check(const unsigned int port, const unsigned int idx) { @@ -4477,7 +4468,6 @@ sh_css_get_mipi_sizes_for_check(const unsigned int port, const unsigned int idx) port, idx, my_css.mipi_sizes_for_check[port][idx]); return my_css.mipi_sizes_for_check[port][idx]; } -#endif static int sh_css_pipe_configure_output( struct ia_css_pipe *pipe, @@ -8592,15 +8582,13 @@ ia_css_stream_start(struct ia_css_stream *stream) return err; } -#if defined(ISP2401) - if ((stream->config.mode == IA_CSS_INPUT_MODE_SENSOR) || - (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR)) + if (IS_ISP2401 && + ((stream->config.mode == IA_CSS_INPUT_MODE_SENSOR) || + (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR))) stream_register_with_csi_rx(stream); -#endif -#if !defined(ISP2401) /* Initialize mipi size checks */ - if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { + if (!IS_ISP2401 && stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { unsigned int idx; unsigned int port = (unsigned int)(stream->config.source.port.port); @@ -8609,10 +8597,12 @@ ia_css_stream_start(struct ia_css_stream *stream) sh_css_get_mipi_sizes_for_check(port, idx); } } -#endif if (stream->config.mode != IA_CSS_INPUT_MODE_MEMORY) { - err = sh_css_config_input_network(stream); + if (IS_ISP2401) + err = sh_css_config_input_network_2401(stream); + else + err = sh_css_config_input_network_2400(stream); if (err) return err; } -- GitLab From 113401c6738643fbdc8f3010cdac4166106b4683 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Wed, 2 Aug 2023 11:56:04 +0200 Subject: [PATCH 0356/1451] media: atomisp: sh_css: Removed #ifdef ISP2401 to make code generic Removed #ifdef ISP2401 to allow the destroy function can destroy the data of both types of ISP. Link: https://lore.kernel.org/r/20230802095606.1298152-11-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css.c | 74 +++++++++++----------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index 94cb48fa59a2f..28f5184635887 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -8450,46 +8450,48 @@ ia_css_stream_destroy(struct ia_css_stream *stream) if ((stream->last_pipe) && ia_css_pipeline_is_mapped(stream->last_pipe->pipe_num)) { -#if defined(ISP2401) - for (i = 0; i < stream->num_pipes; i++) { - struct ia_css_pipe *entry = stream->pipes[i]; - unsigned int sp_thread_id; - struct sh_css_sp_pipeline_terminal *sp_pipeline_input_terminal; - - assert(entry); - if (entry) { - /* get the SP thread id */ - if (!ia_css_pipeline_get_sp_thread_id( - ia_css_pipe_get_pipe_num(entry), &sp_thread_id)) - return -EINVAL; - /* get the target input terminal */ - sp_pipeline_input_terminal = - &sh_css_sp_group.pipe_io[sp_thread_id].input; - - for (i = 0; i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++) { - ia_css_isys_stream_h isys_stream = - &sp_pipeline_input_terminal->context.virtual_input_system_stream[i]; - if (stream->config.isys_config[i].valid && isys_stream->valid) - ia_css_isys_stream_destroy(isys_stream); - } - } - } - if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { + if (IS_ISP2401) { for (i = 0; i < stream->num_pipes; i++) { struct ia_css_pipe *entry = stream->pipes[i]; - /* - * free any mipi frames that are remaining: - * some test stream create-destroy cycles do - * not generate output frames - * and the mipi buffer is not freed in the - * deque function - */ - if (entry) - free_mipi_frames(entry); + unsigned int sp_thread_id; + struct sh_css_sp_pipeline_terminal *sp_pipeline_input_terminal; + + assert(entry); + if (entry) { + /* get the SP thread id */ + if (!ia_css_pipeline_get_sp_thread_id( + ia_css_pipe_get_pipe_num(entry), &sp_thread_id)) + return -EINVAL; + + /* get the target input terminal */ + sp_pipeline_input_terminal = + &sh_css_sp_group.pipe_io[sp_thread_id].input; + + for (i = 0; i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++) { + ia_css_isys_stream_h isys_stream = + &sp_pipeline_input_terminal->context.virtual_input_system_stream[i]; + if (stream->config.isys_config[i].valid && isys_stream->valid) + ia_css_isys_stream_destroy(isys_stream); + } + } } + + if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { + for (i = 0; i < stream->num_pipes; i++) { + struct ia_css_pipe *entry = stream->pipes[i]; + /* + * free any mipi frames that are remaining: + * some test stream create-destroy cycles do + * not generate output frames + * and the mipi buffer is not freed in the + * deque function + */ + if (entry) + free_mipi_frames(entry); + } + } + stream_unregister_with_csi_rx(stream); } - stream_unregister_with_csi_rx(stream); -#endif for (i = 0; i < stream->num_pipes; i++) { struct ia_css_pipe *curr_pipe = stream->pipes[i]; -- GitLab From ec1f9f15a9c28bd22769e9f37ba14bacf2178048 Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Wed, 2 Aug 2023 11:56:05 +0200 Subject: [PATCH 0357/1451] media: atomisp: sh_css: Removed #ifdef ISP2401 to make the driver generic Removed #ifdef ISP2401 to make the driver generic. Link: https://lore.kernel.org/r/20230802095606.1298152-12-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css.c | 42 +++++++++------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index 28f5184635887..81f18db7316c9 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -1298,9 +1298,7 @@ sh_css_invalidate_shading_tables(struct ia_css_stream *stream) static void enable_interrupts(enum ia_css_irq_type irq_type) { -#ifndef ISP2401 enum mipi_port_id port; -#endif bool enable_pulse = irq_type != IA_CSS_IRQ_TYPE_EDGE; IA_CSS_ENTER_PRIVATE(""); @@ -1321,10 +1319,10 @@ enable_interrupts(enum ia_css_irq_type irq_type) (enum virq_id)(IRQ_SW_CHANNEL1_ID + IRQ_SW_CHANNEL_OFFSET), true); -#ifndef ISP2401 - for (port = 0; port < N_MIPI_PORT_ID; port++) - ia_css_isys_rx_enable_all_interrupts(port); -#endif + if (!IS_ISP2401) { + for (port = 0; port < N_MIPI_PORT_ID; port++) + ia_css_isys_rx_enable_all_interrupts(port); + } IA_CSS_LEAVE_PRIVATE(""); } @@ -2160,10 +2158,10 @@ ia_css_uninit(void) ia_css_rmgr_uninit(); -#if !defined(ISP2401) - /* needed for reprogramming the inputformatter after power cycle of css */ - ifmtr_set_if_blocking_mode_reset = true; -#endif + if (!IS_ISP2401) { + /* needed for reprogramming the inputformatter after power cycle of css */ + ifmtr_set_if_blocking_mode_reset = true; + } if (!fw_explicitly_loaded) ia_css_unload_firmware(); @@ -3117,9 +3115,10 @@ init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe, ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_INPUT_FRAME, thread_id, &queue_id); in_frame->dynamic_queue_id = queue_id; in_frame->buf_type = IA_CSS_BUFFER_TYPE_INPUT_FRAME; -#ifdef ISP2401 - ia_css_get_crop_offsets(pipe, &in_frame->frame_info); -#endif + + if (IS_ISP2401) + ia_css_get_crop_offsets(pipe, &in_frame->frame_info); + err = ia_css_frame_init_planes(in_frame); ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "%s() bayer_order = %d\n", @@ -7365,19 +7364,18 @@ static int capture_start(struct ia_css_pipe *pipe) start_pipe(pipe, copy_ovrd, pipe->stream->config.mode); -#if !defined(ISP2401) /* * old isys: for IA_CSS_PIPE_MODE_COPY pipe, isys rx has to be configured, * which is currently done in start_binary(); but COPY pipe contains no binary, * and does not call start_binary(); so we need to configure the rx here. */ - if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY && + if (!IS_ISP2401 && + pipe->config.mode == IA_CSS_PIPE_MODE_COPY && pipe->stream->reconfigure_css_rx) { ia_css_isys_rx_configure(&pipe->stream->csi_rx_config, pipe->stream->config.mode); pipe->stream->reconfigure_css_rx = false; } -#endif IA_CSS_LEAVE_ERR_PRIVATE(err); return err; @@ -7599,11 +7597,8 @@ void ia_css_stream_request_flash(struct ia_css_stream *stream) ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_request_flash() enter: void\n"); -#ifndef ISP2401 - sh_css_write_host2sp_command(host2sp_cmd_start_flash); -#else - if (sh_css_sp_is_running()) { - if (!sh_css_write_host2sp_command(host2sp_cmd_start_flash)) { + if (!IS_ISP2401 || sh_css_sp_is_running()) { + if (!sh_css_write_host2sp_command(host2sp_cmd_start_flash) && IS_ISP2401) { IA_CSS_ERROR("Call to 'sh-css_write_host2sp_command()' failed"); ia_css_debug_dump_sp_sw_debug_info(); } @@ -7611,7 +7606,6 @@ void ia_css_stream_request_flash(struct ia_css_stream *stream) IA_CSS_LOG("SP is not running!"); } -#endif ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_request_flash() leave: return_void\n"); } @@ -8625,16 +8619,14 @@ ia_css_stream_stop(struct ia_css_stream *stream) ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_stop: stopping %d\n", stream->last_pipe->mode); -#if !defined(ISP2401) /* De-initialize mipi size checks */ - if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { + if (!IS_ISP2401 && stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { unsigned int idx; unsigned int port = (unsigned int)(stream->config.source.port.port); for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT; idx++) sh_css_sp_group.config.mipi_sizes_for_check[port][idx] = 0; } -#endif err = ia_css_pipeline_request_stop(&stream->last_pipe->pipeline); if (err) -- GitLab From 65214188ca1dbaa390edbae20ae31d210da7c46b Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Wed, 2 Aug 2023 11:56:06 +0200 Subject: [PATCH 0358/1451] media: atomisp: atomisp_v4l2: Removed unnecessary code Here is the last step of #ifdef ISP2401 removal work. Since the driver became generic, this part of the code was no longer needed and can be removed. Link: https://lore.kernel.org/r/20230802095606.1298152-13-hpa@redhat.com Signed-off-by: Kate Hsuan Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/atomisp/pci/atomisp_v4l2.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c index 0d0329f5e4ad1..c1c8501ec61f5 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c @@ -1206,25 +1206,6 @@ static bool is_valid_device(struct pci_dev *pdev, const struct pci_device_id *id return false; } - /* - * FIXME: - * remove the if once the driver become generic - */ - -#ifndef ISP2401 - if (IS_ISP2401) { - dev_err(&pdev->dev, "Support for %s (ISP2401) was disabled at compile time\n", - name); - return false; - } -#else - if (!IS_ISP2401) { - dev_err(&pdev->dev, "Support for %s (ISP2400) was disabled at compile time\n", - name); - return false; - } -#endif - dev_info(&pdev->dev, "Detected %s version %d (ISP240%c) on %s\n", name, pdev->revision, IS_ISP2401 ? '1' : '0', product); -- GitLab From 42c26b4cd1f725653476c5423d260609b6446fea Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 12 Aug 2023 12:46:12 +0200 Subject: [PATCH 0359/1451] media: atomisp: Simplify some if (IS_ISP2401...) statements Replace: if (!IS_ISP2401 || (IS_ISP2401 && xxx)) with: if (!IS_ISP2401 || xxx) If the right side of the '||' needs to be evaluated then it is already known that IS_ISP2401 is true, so no need to check for it. Link: https://lore.kernel.org/r/20230812104612.38806-1-hdegoede@redhat.com Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index 81f18db7316c9..f35c90809414c 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -7351,7 +7351,7 @@ static int capture_start(struct ia_css_pipe *pipe) } } /* old isys: need to send_mipi_frames() in all pipe modes */ - if (!IS_ISP2401 || (IS_ISP2401 && pipe->config.mode != IA_CSS_PIPE_MODE_COPY)) { + if (!IS_ISP2401 || pipe->config.mode != IA_CSS_PIPE_MODE_COPY) { err = send_mipi_frames(pipe); if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); @@ -8077,7 +8077,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, /* check if mipi size specified */ if (stream_config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) - if (!IS_ISP2401 || (IS_ISP2401 && !stream_config->online)) + if (!IS_ISP2401 || !stream_config->online) { unsigned int port = (unsigned int)stream_config->source.port.port; -- GitLab From 00c408775ade09cfa16b300db43b0b7be48197e6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 12 Aug 2023 15:35:22 +0200 Subject: [PATCH 0360/1451] media: atomisp: Drop ia_css_debug_dump_debug_info() and functions only used by it ia_css_debug_dump_debug_info() is defined but never called anywhere, drop it. Also drop all the other ia_css_debug_dump_* functions only called by ia_css_debug_dump_debug_info(), as well as *_get_state() functions only used by those. Link: https://lore.kernel.org/r/20230812133523.355581-1-hdegoede@redhat.com Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../pci/hive_isp_css_common/host/dma.c | 266 ---- .../pci/hive_isp_css_common/host/dma_local.h | 116 -- .../hive_isp_css_common/host/input_system.c | 371 ------ .../pci/hive_isp_css_common/host/irq.c | 19 - .../pci/hive_isp_css_common/host/irq_local.h | 8 - .../pci/hive_isp_css_common/host/isp.c | 60 - .../pci/hive_isp_css_common/host/isp_local.h | 31 - .../atomisp/pci/hive_isp_css_common/host/sp.c | 47 - .../pci/hive_isp_css_common/host/sp_local.h | 26 - .../hive_isp_css_include/host/dma_public.h | 13 - .../hive_isp_css_include/host/irq_public.h | 10 - .../hive_isp_css_include/host/isp_public.h | 13 - .../pci/hive_isp_css_include/host/sp_public.h | 16 - .../atomisp/pci/isp2400_input_system_local.h | 113 -- .../atomisp/pci/isp2400_input_system_public.h | 28 - .../runtime/debug/interface/ia_css_debug.h | 67 -- .../pci/runtime/debug/src/ia_css_debug.c | 1072 ----------------- 17 files changed, 2276 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma.c index f85950c471c79..0b6647b2eb764 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma.c @@ -23,272 +23,6 @@ #include "dma_private.h" #endif /* __INLINE_DMA__ */ -void dma_get_state(const dma_ID_t ID, dma_state_t *state) -{ - int i; - hrt_data tmp; - - assert(ID < N_DMA_ID); - assert(state); - - tmp = dma_reg_load(ID, DMA_COMMAND_FSM_REG_IDX); - //reg [3:0] : flags error [3], stall, run, idle [0] - //reg [9:4] : command - //reg[14:10] : channel - //reg [23:15] : param - state->fsm_command_idle = tmp & 0x1; - state->fsm_command_run = tmp & 0x2; - state->fsm_command_stalling = tmp & 0x4; - state->fsm_command_error = tmp & 0x8; - state->last_command_channel = (tmp >> 10 & 0x1F); - state->last_command_param = (tmp >> 15 & 0x0F); - tmp = (tmp >> 4) & 0x3F; - /* state->last_command = (dma_commands_t)tmp; */ - /* if the enumerator is made non-linear */ - /* AM: the list below does not cover all the cases*/ - /* and these are not correct */ - /* therefore for just dumpinmg this command*/ - state->last_command = tmp; - - /* - if (tmp == 0) - state->last_command = DMA_COMMAND_READ; - if (tmp == 1) - state->last_command = DMA_COMMAND_WRITE; - if (tmp == 2) - state->last_command = DMA_COMMAND_SET_CHANNEL; - if (tmp == 3) - state->last_command = DMA_COMMAND_SET_PARAM; - if (tmp == 4) - state->last_command = DMA_COMMAND_READ_SPECIFIC; - if (tmp == 5) - state->last_command = DMA_COMMAND_WRITE_SPECIFIC; - if (tmp == 8) - state->last_command = DMA_COMMAND_INIT; - if (tmp == 12) - state->last_command = DMA_COMMAND_INIT_SPECIFIC; - if (tmp == 15) - state->last_command = DMA_COMMAND_RST; - */ - - /* No sub-fields, idx = 0 */ - state->current_command = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX(0, _DMA_FSM_GROUP_CMD_IDX)); - state->current_addr_a = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX(0, _DMA_FSM_GROUP_ADDR_A_IDX)); - state->current_addr_b = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX(0, _DMA_FSM_GROUP_ADDR_B_IDX)); - - tmp = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_CTRL_STATE_IDX, - _DMA_FSM_GROUP_FSM_CTRL_IDX)); - state->fsm_ctrl_idle = tmp & 0x1; - state->fsm_ctrl_run = tmp & 0x2; - state->fsm_ctrl_stalling = tmp & 0x4; - state->fsm_ctrl_error = tmp & 0x8; - tmp = tmp >> 4; - /* state->fsm_ctrl_state = (dma_ctrl_states_t)tmp; */ - if (tmp == 0) - state->fsm_ctrl_state = DMA_CTRL_STATE_IDLE; - if (tmp == 1) - state->fsm_ctrl_state = DMA_CTRL_STATE_REQ_RCV; - if (tmp == 2) - state->fsm_ctrl_state = DMA_CTRL_STATE_RCV; - if (tmp == 3) - state->fsm_ctrl_state = DMA_CTRL_STATE_RCV_REQ; - if (tmp == 4) - state->fsm_ctrl_state = DMA_CTRL_STATE_INIT; - state->fsm_ctrl_source_dev = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_CTRL_REQ_DEV_IDX, - _DMA_FSM_GROUP_FSM_CTRL_IDX)); - state->fsm_ctrl_source_addr = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_CTRL_REQ_ADDR_IDX, - _DMA_FSM_GROUP_FSM_CTRL_IDX)); - state->fsm_ctrl_source_stride = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_CTRL_REQ_STRIDE_IDX, - _DMA_FSM_GROUP_FSM_CTRL_IDX)); - state->fsm_ctrl_source_width = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_CTRL_REQ_XB_IDX, - _DMA_FSM_GROUP_FSM_CTRL_IDX)); - state->fsm_ctrl_source_height = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_CTRL_REQ_YB_IDX, - _DMA_FSM_GROUP_FSM_CTRL_IDX)); - state->fsm_ctrl_pack_source_dev = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_CTRL_PACK_REQ_DEV_IDX, - _DMA_FSM_GROUP_FSM_CTRL_IDX)); - state->fsm_ctrl_pack_dest_dev = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_CTRL_PACK_WR_DEV_IDX, - _DMA_FSM_GROUP_FSM_CTRL_IDX)); - state->fsm_ctrl_dest_addr = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_CTRL_WR_ADDR_IDX, - _DMA_FSM_GROUP_FSM_CTRL_IDX)); - state->fsm_ctrl_dest_stride = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_CTRL_WR_STRIDE_IDX, - _DMA_FSM_GROUP_FSM_CTRL_IDX)); - state->fsm_ctrl_pack_source_width = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_CTRL_PACK_REQ_XB_IDX, - _DMA_FSM_GROUP_FSM_CTRL_IDX)); - state->fsm_ctrl_pack_dest_height = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_CTRL_PACK_WR_YB_IDX, - _DMA_FSM_GROUP_FSM_CTRL_IDX)); - state->fsm_ctrl_pack_dest_width = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_CTRL_PACK_WR_XB_IDX, - _DMA_FSM_GROUP_FSM_CTRL_IDX)); - state->fsm_ctrl_pack_source_elems = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_CTRL_PACK_ELEM_REQ_IDX, - _DMA_FSM_GROUP_FSM_CTRL_IDX)); - state->fsm_ctrl_pack_dest_elems = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_CTRL_PACK_ELEM_WR_IDX, - _DMA_FSM_GROUP_FSM_CTRL_IDX)); - state->fsm_ctrl_pack_extension = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_CTRL_PACK_S_Z_IDX, - _DMA_FSM_GROUP_FSM_CTRL_IDX)); - - tmp = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_PACK_STATE_IDX, - _DMA_FSM_GROUP_FSM_PACK_IDX)); - state->pack_idle = tmp & 0x1; - state->pack_run = tmp & 0x2; - state->pack_stalling = tmp & 0x4; - state->pack_error = tmp & 0x8; - state->pack_cnt_height = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_PACK_CNT_YB_IDX, - _DMA_FSM_GROUP_FSM_PACK_IDX)); - state->pack_src_cnt_width = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_PACK_CNT_XB_REQ_IDX, - _DMA_FSM_GROUP_FSM_PACK_IDX)); - state->pack_dest_cnt_width = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_PACK_CNT_XB_WR_IDX, - _DMA_FSM_GROUP_FSM_PACK_IDX)); - - tmp = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_REQ_STATE_IDX, - _DMA_FSM_GROUP_FSM_REQ_IDX)); - /* state->read_state = (dma_rw_states_t)tmp; */ - if (tmp == 0) - state->read_state = DMA_RW_STATE_IDLE; - if (tmp == 1) - state->read_state = DMA_RW_STATE_REQ; - if (tmp == 2) - state->read_state = DMA_RW_STATE_NEXT_LINE; - if (tmp == 3) - state->read_state = DMA_RW_STATE_UNLOCK_CHANNEL; - state->read_cnt_height = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_REQ_CNT_YB_IDX, - _DMA_FSM_GROUP_FSM_REQ_IDX)); - state->read_cnt_width = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_REQ_CNT_XB_IDX, - _DMA_FSM_GROUP_FSM_REQ_IDX)); - - tmp = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_WR_STATE_IDX, - _DMA_FSM_GROUP_FSM_WR_IDX)); - /* state->write_state = (dma_rw_states_t)tmp; */ - if (tmp == 0) - state->write_state = DMA_RW_STATE_IDLE; - if (tmp == 1) - state->write_state = DMA_RW_STATE_REQ; - if (tmp == 2) - state->write_state = DMA_RW_STATE_NEXT_LINE; - if (tmp == 3) - state->write_state = DMA_RW_STATE_UNLOCK_CHANNEL; - state->write_height = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_WR_CNT_YB_IDX, - _DMA_FSM_GROUP_FSM_WR_IDX)); - state->write_width = dma_reg_load(ID, - DMA_CG_INFO_REG_IDX( - _DMA_FSM_GROUP_FSM_WR_CNT_XB_IDX, - _DMA_FSM_GROUP_FSM_WR_IDX)); - - for (i = 0; i < HIVE_ISP_NUM_DMA_CONNS; i++) { - dma_port_state_t *port = &state->port_states[i]; - - tmp = dma_reg_load(ID, DMA_DEV_INFO_REG_IDX(0, i)); - port->req_cs = ((tmp & 0x1) != 0); - port->req_we_n = ((tmp & 0x2) != 0); - port->req_run = ((tmp & 0x4) != 0); - port->req_ack = ((tmp & 0x8) != 0); - - tmp = dma_reg_load(ID, DMA_DEV_INFO_REG_IDX(1, i)); - port->send_cs = ((tmp & 0x1) != 0); - port->send_we_n = ((tmp & 0x2) != 0); - port->send_run = ((tmp & 0x4) != 0); - port->send_ack = ((tmp & 0x8) != 0); - - tmp = dma_reg_load(ID, DMA_DEV_INFO_REG_IDX(2, i)); - if (tmp & 0x1) - port->fifo_state = DMA_FIFO_STATE_WILL_BE_FULL; - if (tmp & 0x2) - port->fifo_state = DMA_FIFO_STATE_FULL; - if (tmp & 0x4) - port->fifo_state = DMA_FIFO_STATE_EMPTY; - port->fifo_counter = tmp >> 3; - } - - for (i = 0; i < HIVE_DMA_NUM_CHANNELS; i++) { - dma_channel_state_t *ch = &state->channel_states[i]; - - ch->connection = DMA_GET_CONNECTION(dma_reg_load(ID, - DMA_CHANNEL_PARAM_REG_IDX(i, - _DMA_PACKING_SETUP_PARAM))); - ch->sign_extend = DMA_GET_EXTENSION(dma_reg_load(ID, - DMA_CHANNEL_PARAM_REG_IDX(i, - _DMA_PACKING_SETUP_PARAM))); - ch->height = dma_reg_load(ID, - DMA_CHANNEL_PARAM_REG_IDX(i, - _DMA_HEIGHT_PARAM)); - ch->stride_a = dma_reg_load(ID, - DMA_CHANNEL_PARAM_REG_IDX(i, - _DMA_STRIDE_A_PARAM)); - ch->elems_a = DMA_GET_ELEMENTS(dma_reg_load(ID, - DMA_CHANNEL_PARAM_REG_IDX(i, - _DMA_ELEM_CROPPING_A_PARAM))); - ch->cropping_a = DMA_GET_CROPPING(dma_reg_load(ID, - DMA_CHANNEL_PARAM_REG_IDX(i, - _DMA_ELEM_CROPPING_A_PARAM))); - ch->width_a = dma_reg_load(ID, - DMA_CHANNEL_PARAM_REG_IDX(i, - _DMA_WIDTH_A_PARAM)); - ch->stride_b = dma_reg_load(ID, - DMA_CHANNEL_PARAM_REG_IDX(i, - _DMA_STRIDE_B_PARAM)); - ch->elems_b = DMA_GET_ELEMENTS(dma_reg_load(ID, - DMA_CHANNEL_PARAM_REG_IDX(i, - _DMA_ELEM_CROPPING_B_PARAM))); - ch->cropping_b = DMA_GET_CROPPING(dma_reg_load(ID, - DMA_CHANNEL_PARAM_REG_IDX(i, - _DMA_ELEM_CROPPING_B_PARAM))); - ch->width_b = dma_reg_load(ID, - DMA_CHANNEL_PARAM_REG_IDX(i, - _DMA_WIDTH_B_PARAM)); - } -} - void dma_set_max_burst_size(const dma_ID_t ID, dma_connection conn, uint32_t max_burst_size) diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma_local.h index 7e4cc75733cd7..48a1ace79897c 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma_local.h @@ -89,120 +89,4 @@ #define DMA_GET_ELEMENTS(val) _hrt_get_bits(val, _DMA_V2_ELEMENTS_IDX, _DMA_V2_ELEMENTS_BITS) #define DMA_GET_CROPPING(val) _hrt_get_bits(val, _DMA_V2_LEFT_CROPPING_IDX, _DMA_V2_LEFT_CROPPING_BITS) -typedef enum { - DMA_CTRL_STATE_IDLE, - DMA_CTRL_STATE_REQ_RCV, - DMA_CTRL_STATE_RCV, - DMA_CTRL_STATE_RCV_REQ, - DMA_CTRL_STATE_INIT, - N_DMA_CTRL_STATES -} dma_ctrl_states_t; - -typedef enum { - DMA_COMMAND_READ, - DMA_COMMAND_WRITE, - DMA_COMMAND_SET_CHANNEL, - DMA_COMMAND_SET_PARAM, - DMA_COMMAND_READ_SPECIFIC, - DMA_COMMAND_WRITE_SPECIFIC, - DMA_COMMAND_INIT, - DMA_COMMAND_INIT_SPECIFIC, - DMA_COMMAND_RST, - N_DMA_COMMANDS -} dma_commands_t; - -typedef enum { - DMA_RW_STATE_IDLE, - DMA_RW_STATE_REQ, - DMA_RW_STATE_NEXT_LINE, - DMA_RW_STATE_UNLOCK_CHANNEL, - N_DMA_RW_STATES -} dma_rw_states_t; - -typedef enum { - DMA_FIFO_STATE_WILL_BE_FULL, - DMA_FIFO_STATE_FULL, - DMA_FIFO_STATE_EMPTY, - N_DMA_FIFO_STATES -} dma_fifo_states_t; - -/* typedef struct dma_state_s dma_state_t; */ -typedef struct dma_channel_state_s dma_channel_state_t; -typedef struct dma_port_state_s dma_port_state_t; - -struct dma_port_state_s { - bool req_cs; - bool req_we_n; - bool req_run; - bool req_ack; - bool send_cs; - bool send_we_n; - bool send_run; - bool send_ack; - dma_fifo_states_t fifo_state; - int fifo_counter; -}; - -struct dma_channel_state_s { - int connection; - bool sign_extend; - int height; - int stride_a; - int elems_a; - int cropping_a; - int width_a; - int stride_b; - int elems_b; - int cropping_b; - int width_b; -}; - -struct dma_state_s { - bool fsm_command_idle; - bool fsm_command_run; - bool fsm_command_stalling; - bool fsm_command_error; - dma_commands_t last_command; - int last_command_channel; - int last_command_param; - dma_commands_t current_command; - int current_addr_a; - int current_addr_b; - bool fsm_ctrl_idle; - bool fsm_ctrl_run; - bool fsm_ctrl_stalling; - bool fsm_ctrl_error; - dma_ctrl_states_t fsm_ctrl_state; - int fsm_ctrl_source_dev; - int fsm_ctrl_source_addr; - int fsm_ctrl_source_stride; - int fsm_ctrl_source_width; - int fsm_ctrl_source_height; - int fsm_ctrl_pack_source_dev; - int fsm_ctrl_pack_dest_dev; - int fsm_ctrl_dest_addr; - int fsm_ctrl_dest_stride; - int fsm_ctrl_pack_source_width; - int fsm_ctrl_pack_dest_height; - int fsm_ctrl_pack_dest_width; - int fsm_ctrl_pack_source_elems; - int fsm_ctrl_pack_dest_elems; - int fsm_ctrl_pack_extension; - int pack_idle; - int pack_run; - int pack_stalling; - int pack_error; - int pack_cnt_height; - int pack_src_cnt_width; - int pack_dest_cnt_width; - dma_rw_states_t read_state; - int read_cnt_height; - int read_cnt_width; - dma_rw_states_t write_state; - int write_height; - int write_width; - dma_port_state_t port_states[HIVE_ISP_NUM_DMA_CONNS]; - dma_channel_state_t channel_states[HIVE_DMA_NUM_CHANNELS]; -}; - #endif /* __DMA_LOCAL_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c index c60f0d5b01c65..ca1ce66890349 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c @@ -79,31 +79,6 @@ static input_system_err_t input_system_multiplexer_cfg( const input_system_multiplex_t rhs, input_system_config_flags_t *const flags); -static inline void capture_unit_get_state( - const input_system_ID_t ID, - const sub_system_ID_t sub_id, - capture_unit_state_t *state); - -static inline void acquisition_unit_get_state( - const input_system_ID_t ID, - const sub_system_ID_t sub_id, - acquisition_unit_state_t *state); - -static inline void ctrl_unit_get_state( - const input_system_ID_t ID, - const sub_system_ID_t sub_id, - ctrl_unit_state_t *state); - -static inline void mipi_port_get_state( - const rx_ID_t ID, - const enum mipi_port_id port_ID, - mipi_port_state_t *state); - -static inline void rx_channel_get_state( - const rx_ID_t ID, - const unsigned int ch_id, - rx_channel_state_t *state); - static void gp_device_rst(const gp_device_ID_t ID); static void input_selector_cfg_for_sensor(const gp_device_ID_t ID); @@ -115,76 +90,6 @@ static void input_switch_cfg( const input_switch_cfg_t *const cfg ); -void receiver_get_state( - const rx_ID_t ID, - receiver_state_t *state) -{ - enum mipi_port_id port_id; - unsigned int ch_id; - - assert(ID < N_RX_ID); - assert(state); - - state->fs_to_ls_delay = (uint8_t)receiver_reg_load(ID, - _HRT_CSS_RECEIVER_FS_TO_LS_DELAY_REG_IDX); - state->ls_to_data_delay = (uint8_t)receiver_reg_load(ID, - _HRT_CSS_RECEIVER_LS_TO_DATA_DELAY_REG_IDX); - state->data_to_le_delay = (uint8_t)receiver_reg_load(ID, - _HRT_CSS_RECEIVER_DATA_TO_LE_DELAY_REG_IDX); - state->le_to_fe_delay = (uint8_t)receiver_reg_load(ID, - _HRT_CSS_RECEIVER_LE_TO_FE_DELAY_REG_IDX); - state->fe_to_fs_delay = (uint8_t)receiver_reg_load(ID, - _HRT_CSS_RECEIVER_FE_TO_FS_DELAY_REG_IDX); - state->le_to_fs_delay = (uint8_t)receiver_reg_load(ID, - _HRT_CSS_RECEIVER_LE_TO_LS_DELAY_REG_IDX); - state->is_two_ppc = (bool)receiver_reg_load(ID, - _HRT_CSS_RECEIVER_TWO_PIXEL_EN_REG_IDX); - state->backend_rst = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_BACKEND_RST_REG_IDX); - state->raw18 = (uint16_t)receiver_reg_load(ID, - _HRT_CSS_RECEIVER_RAW18_REG_IDX); - state->force_raw8 = (bool)receiver_reg_load(ID, - _HRT_CSS_RECEIVER_FORCE_RAW8_REG_IDX); - state->raw16 = (uint16_t)receiver_reg_load(ID, - _HRT_CSS_RECEIVER_RAW16_REG_IDX); - - for (port_id = (enum mipi_port_id)0; port_id < N_MIPI_PORT_ID; port_id++) { - mipi_port_get_state(ID, port_id, - &state->mipi_port_state[port_id]); - } - for (ch_id = 0U; ch_id < N_RX_CHANNEL_ID; ch_id++) { - rx_channel_get_state(ID, ch_id, - &state->rx_channel_state[ch_id]); - } - - state->be_gsp_acc_ovl = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_BE_GSP_ACC_OVL_REG_IDX); - state->be_srst = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_BE_SRST_REG_IDX); - state->be_is_two_ppc = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_BE_TWO_PPC_REG_IDX); - state->be_comp_format0 = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_BE_COMP_FORMAT_REG0_IDX); - state->be_comp_format1 = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_BE_COMP_FORMAT_REG1_IDX); - state->be_comp_format2 = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_BE_COMP_FORMAT_REG2_IDX); - state->be_comp_format3 = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_BE_COMP_FORMAT_REG3_IDX); - state->be_sel = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_BE_SEL_REG_IDX); - state->be_raw16_config = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_BE_RAW16_CONFIG_REG_IDX); - state->be_raw18_config = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_BE_RAW18_CONFIG_REG_IDX); - state->be_force_raw8 = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_BE_FORCE_RAW8_REG_IDX); - state->be_irq_status = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_BE_IRQ_STATUS_REG_IDX); - state->be_irq_clear = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_BE_IRQ_CLEAR_REG_IDX); -} - void receiver_set_compression( const rx_ID_t ID, const unsigned int cfg_ID, @@ -287,282 +192,6 @@ void receiver_irq_clear( port_ID, _HRT_CSS_RECEIVER_IRQ_STATUS_REG_IDX, irq_info); } -static inline void capture_unit_get_state( - const input_system_ID_t ID, - const sub_system_ID_t sub_id, - capture_unit_state_t *state) -{ - assert(/*(sub_id >= CAPTURE_UNIT0_ID) &&*/ (sub_id <= CAPTURE_UNIT2_ID)); - assert(state); - - state->StartMode = input_system_sub_system_reg_load(ID, - sub_id, - CAPT_START_MODE_REG_ID); - state->Start_Addr = input_system_sub_system_reg_load(ID, - sub_id, - CAPT_START_ADDR_REG_ID); - state->Mem_Region_Size = input_system_sub_system_reg_load(ID, - sub_id, - CAPT_MEM_REGION_SIZE_REG_ID); - state->Num_Mem_Regions = input_system_sub_system_reg_load(ID, - sub_id, - CAPT_NUM_MEM_REGIONS_REG_ID); -// AM: Illegal read from following registers. - /* state->Init = input_system_sub_system_reg_load(ID, - sub_id, - CAPT_INIT_REG_ID); - state->Start = input_system_sub_system_reg_load(ID, - sub_id, - CAPT_START_REG_ID); - state->Stop = input_system_sub_system_reg_load(ID, - sub_id, - CAPT_STOP_REG_ID); - */ - state->Packet_Length = input_system_sub_system_reg_load(ID, - sub_id, - CAPT_PACKET_LENGTH_REG_ID); - state->Received_Length = input_system_sub_system_reg_load(ID, - sub_id, - CAPT_RECEIVED_LENGTH_REG_ID); - state->Received_Short_Packets = input_system_sub_system_reg_load(ID, - sub_id, - CAPT_RECEIVED_SHORT_PACKETS_REG_ID); - state->Received_Long_Packets = input_system_sub_system_reg_load(ID, - sub_id, - CAPT_RECEIVED_LONG_PACKETS_REG_ID); - state->Last_Command = input_system_sub_system_reg_load(ID, - sub_id, - CAPT_LAST_COMMAND_REG_ID); - state->Next_Command = input_system_sub_system_reg_load(ID, - sub_id, - CAPT_NEXT_COMMAND_REG_ID); - state->Last_Acknowledge = input_system_sub_system_reg_load(ID, - sub_id, - CAPT_LAST_ACKNOWLEDGE_REG_ID); - state->Next_Acknowledge = input_system_sub_system_reg_load(ID, - sub_id, - CAPT_NEXT_ACKNOWLEDGE_REG_ID); - state->FSM_State_Info = input_system_sub_system_reg_load(ID, - sub_id, - CAPT_FSM_STATE_INFO_REG_ID); -} - -static inline void acquisition_unit_get_state( - const input_system_ID_t ID, - const sub_system_ID_t sub_id, - acquisition_unit_state_t *state) -{ - assert(sub_id == ACQUISITION_UNIT0_ID); - assert(state); - - state->Start_Addr = input_system_sub_system_reg_load(ID, - sub_id, - ACQ_START_ADDR_REG_ID); - state->Mem_Region_Size = input_system_sub_system_reg_load(ID, - sub_id, - ACQ_MEM_REGION_SIZE_REG_ID); - state->Num_Mem_Regions = input_system_sub_system_reg_load(ID, - sub_id, - ACQ_NUM_MEM_REGIONS_REG_ID); -// AM: Illegal read from following registers. - /* state->Init = input_system_sub_system_reg_load(ID, - sub_id, - ACQ_INIT_REG_ID); - */ - state->Received_Short_Packets = input_system_sub_system_reg_load(ID, - sub_id, - ACQ_RECEIVED_SHORT_PACKETS_REG_ID); - state->Received_Long_Packets = input_system_sub_system_reg_load(ID, - sub_id, - ACQ_RECEIVED_LONG_PACKETS_REG_ID); - state->Last_Command = input_system_sub_system_reg_load(ID, - sub_id, - ACQ_LAST_COMMAND_REG_ID); - state->Next_Command = input_system_sub_system_reg_load(ID, - sub_id, - ACQ_NEXT_COMMAND_REG_ID); - state->Last_Acknowledge = input_system_sub_system_reg_load(ID, - sub_id, - ACQ_LAST_ACKNOWLEDGE_REG_ID); - state->Next_Acknowledge = input_system_sub_system_reg_load(ID, - sub_id, - ACQ_NEXT_ACKNOWLEDGE_REG_ID); - state->FSM_State_Info = input_system_sub_system_reg_load(ID, - sub_id, - ACQ_FSM_STATE_INFO_REG_ID); - state->Int_Cntr_Info = input_system_sub_system_reg_load(ID, - sub_id, - ACQ_INT_CNTR_INFO_REG_ID); -} - -static inline void ctrl_unit_get_state( - const input_system_ID_t ID, - const sub_system_ID_t sub_id, - ctrl_unit_state_t *state) -{ - assert(sub_id == CTRL_UNIT0_ID); - assert(state); - - state->captA_start_addr = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_CAPT_START_ADDR_A_REG_ID); - state->captB_start_addr = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_CAPT_START_ADDR_B_REG_ID); - state->captC_start_addr = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_CAPT_START_ADDR_C_REG_ID); - state->captA_mem_region_size = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_CAPT_MEM_REGION_SIZE_A_REG_ID); - state->captB_mem_region_size = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_CAPT_MEM_REGION_SIZE_B_REG_ID); - state->captC_mem_region_size = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_CAPT_MEM_REGION_SIZE_C_REG_ID); - state->captA_num_mem_regions = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_CAPT_NUM_MEM_REGIONS_A_REG_ID); - state->captB_num_mem_regions = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_CAPT_NUM_MEM_REGIONS_B_REG_ID); - state->captC_num_mem_regions = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_CAPT_NUM_MEM_REGIONS_C_REG_ID); - state->acq_start_addr = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_ACQ_START_ADDR_REG_ID); - state->acq_mem_region_size = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_ACQ_MEM_REGION_SIZE_REG_ID); - state->acq_num_mem_regions = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_ACQ_NUM_MEM_REGIONS_REG_ID); -// AM: Illegal read from following registers. - /* state->ctrl_init = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_INIT_REG_ID); - */ - state->last_cmd = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_LAST_COMMAND_REG_ID); - state->next_cmd = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_NEXT_COMMAND_REG_ID); - state->last_ack = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_LAST_ACKNOWLEDGE_REG_ID); - state->next_ack = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_NEXT_ACKNOWLEDGE_REG_ID); - state->top_fsm_state = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_FSM_STATE_INFO_REG_ID); - state->captA_fsm_state = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_CAPT_A_FSM_STATE_INFO_REG_ID); - state->captB_fsm_state = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_CAPT_B_FSM_STATE_INFO_REG_ID); - state->captC_fsm_state = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_CAPT_C_FSM_STATE_INFO_REG_ID); - state->acq_fsm_state = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_ACQ_FSM_STATE_INFO_REG_ID); - state->capt_reserve_one_mem_region = input_system_sub_system_reg_load(ID, - sub_id, - ISYS_CTRL_CAPT_RESERVE_ONE_MEM_REGION_REG_ID); -} - -static inline void mipi_port_get_state( - const rx_ID_t ID, - const enum mipi_port_id port_ID, - mipi_port_state_t *state) -{ - int i; - - assert(ID < N_RX_ID); - assert(port_ID < N_MIPI_PORT_ID); - assert(state); - - state->device_ready = receiver_port_reg_load(ID, - port_ID, _HRT_CSS_RECEIVER_DEVICE_READY_REG_IDX); - state->irq_status = receiver_port_reg_load(ID, - port_ID, _HRT_CSS_RECEIVER_IRQ_STATUS_REG_IDX); - state->irq_enable = receiver_port_reg_load(ID, - port_ID, _HRT_CSS_RECEIVER_IRQ_ENABLE_REG_IDX); - state->timeout_count = receiver_port_reg_load(ID, - port_ID, _HRT_CSS_RECEIVER_TIMEOUT_COUNT_REG_IDX); - state->init_count = (uint16_t)receiver_port_reg_load(ID, - port_ID, _HRT_CSS_RECEIVER_INIT_COUNT_REG_IDX); - state->raw16_18 = (uint16_t)receiver_port_reg_load(ID, - port_ID, _HRT_CSS_RECEIVER_RAW16_18_DATAID_REG_IDX); - state->sync_count = receiver_port_reg_load(ID, - port_ID, _HRT_CSS_RECEIVER_SYNC_COUNT_REG_IDX); - state->rx_count = receiver_port_reg_load(ID, - port_ID, _HRT_CSS_RECEIVER_RX_COUNT_REG_IDX); - - for (i = 0; i < MIPI_4LANE_CFG ; i++) { - state->lane_sync_count[i] = (uint8_t)((state->sync_count) >> (i * 8)); - state->lane_rx_count[i] = (uint8_t)((state->rx_count) >> (i * 8)); - } -} - -static inline void rx_channel_get_state( - const rx_ID_t ID, - const unsigned int ch_id, - rx_channel_state_t *state) -{ - int i; - - assert(ID < N_RX_ID); - assert(ch_id < N_RX_CHANNEL_ID); - assert(state); - - switch (ch_id) { - case 0: - state->comp_scheme0 = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_2400_COMP_SCHEME_VC0_REG0_IDX); - state->comp_scheme1 = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_2400_COMP_SCHEME_VC0_REG1_IDX); - break; - case 1: - state->comp_scheme0 = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_2400_COMP_SCHEME_VC1_REG0_IDX); - state->comp_scheme1 = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_2400_COMP_SCHEME_VC1_REG1_IDX); - break; - case 2: - state->comp_scheme0 = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_2400_COMP_SCHEME_VC2_REG0_IDX); - state->comp_scheme1 = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_2400_COMP_SCHEME_VC2_REG1_IDX); - break; - case 3: - state->comp_scheme0 = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_2400_COMP_SCHEME_VC3_REG0_IDX); - state->comp_scheme1 = receiver_reg_load(ID, - _HRT_CSS_RECEIVER_2400_COMP_SCHEME_VC3_REG1_IDX); - break; - } - - /* See Table 7.1.17,..., 7.1.24 */ - for (i = 0; i < 6; i++) { - u8 val = (uint8_t)((state->comp_scheme0) >> (i * 5)) & 0x1f; - - state->comp[i] = (mipi_compressor_t)(val & 0x07); - state->pred[i] = (mipi_predictor_t)((val & 0x18) >> 3); - } - for (i = 6; i < N_MIPI_FORMAT_CUSTOM; i++) { - u8 val = (uint8_t)((state->comp_scheme0) >> ((i - 6) * 5)) & 0x1f; - - state->comp[i] = (mipi_compressor_t)(val & 0x07); - state->pred[i] = (mipi_predictor_t)((val & 0x18) >> 3); - } -} - // MW: "2400" in the name is not good, but this is to avoid a naming conflict static input_system_cfg2400_t config; diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/irq.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/irq.c index 80b5fd0dc9f6e..4697d8d7b915b 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/irq.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/irq.c @@ -225,25 +225,6 @@ void irq_raise( return; } -void irq_controller_get_state(const irq_ID_t ID, - struct irq_controller_state *state) -{ - assert(ID < N_IRQ_ID); - assert(state); - - state->irq_edge = irq_reg_load(ID, - _HRT_IRQ_CONTROLLER_EDGE_REG_IDX); - state->irq_mask = irq_reg_load(ID, - _HRT_IRQ_CONTROLLER_MASK_REG_IDX); - state->irq_status = irq_reg_load(ID, - _HRT_IRQ_CONTROLLER_STATUS_REG_IDX); - state->irq_enable = irq_reg_load(ID, - _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX); - state->irq_level_not_pulse = irq_reg_load(ID, - _HRT_IRQ_CONTROLLER_EDGE_NOT_PULSE_REG_IDX); - return; -} - bool any_virq_signal(void) { unsigned int irq_status = irq_reg_load(IRQ0_ID, diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/irq_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/irq_local.h index 6a25345ae88ed..8fd1bce852145 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/irq_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/irq_local.h @@ -115,12 +115,4 @@ struct virq_info { hrt_data irq_status_reg[N_IRQ_ID]; }; -struct irq_controller_state { - unsigned int irq_edge; - unsigned int irq_mask; - unsigned int irq_status; - unsigned int irq_enable; - unsigned int irq_level_not_pulse; -}; - #endif /* __IRQ_LOCAL_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/isp.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/isp.c index 4ad5e2db8a89b..b78cc324da6a7 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/isp.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/isp.c @@ -39,66 +39,6 @@ void cnd_isp_irq_enable( return; } -void isp_get_state( - const isp_ID_t ID, - isp_state_t *state, - isp_stall_t *stall) -{ - hrt_data sc = isp_ctrl_load(ID, ISP_SC_REG); - - assert(state); - assert(stall); - -#if defined(_hrt_sysmem_ident_address) - /* Patch to avoid compiler unused symbol warning in C_RUN build */ - (void)__hrt_sysmem_ident_address; - (void)_hrt_sysmem_map_var; -#endif - - state->pc = isp_ctrl_load(ID, ISP_PC_REG); - state->status_register = sc; - state->is_broken = isp_ctrl_getbit(ID, ISP_SC_REG, ISP_BROKEN_BIT); - state->is_idle = isp_ctrl_getbit(ID, ISP_SC_REG, ISP_IDLE_BIT); - state->is_sleeping = isp_ctrl_getbit(ID, ISP_SC_REG, ISP_SLEEPING_BIT); - state->is_stalling = isp_ctrl_getbit(ID, ISP_SC_REG, ISP_STALLING_BIT); - stall->stat_ctrl = - !isp_ctrl_getbit(ID, ISP_CTRL_SINK_REG, ISP_CTRL_SINK_BIT); - stall->pmem = - !isp_ctrl_getbit(ID, ISP_PMEM_SINK_REG, ISP_PMEM_SINK_BIT); - stall->dmem = - !isp_ctrl_getbit(ID, ISP_DMEM_SINK_REG, ISP_DMEM_SINK_BIT); - stall->vmem = - !isp_ctrl_getbit(ID, ISP_VMEM_SINK_REG, ISP_VMEM_SINK_BIT); - stall->fifo0 = - !isp_ctrl_getbit(ID, ISP_FIFO0_SINK_REG, ISP_FIFO0_SINK_BIT); - stall->fifo1 = - !isp_ctrl_getbit(ID, ISP_FIFO1_SINK_REG, ISP_FIFO1_SINK_BIT); - stall->fifo2 = - !isp_ctrl_getbit(ID, ISP_FIFO2_SINK_REG, ISP_FIFO2_SINK_BIT); - stall->fifo3 = - !isp_ctrl_getbit(ID, ISP_FIFO3_SINK_REG, ISP_FIFO3_SINK_BIT); - stall->fifo4 = - !isp_ctrl_getbit(ID, ISP_FIFO4_SINK_REG, ISP_FIFO4_SINK_BIT); - stall->fifo5 = - !isp_ctrl_getbit(ID, ISP_FIFO5_SINK_REG, ISP_FIFO5_SINK_BIT); - stall->fifo6 = - !isp_ctrl_getbit(ID, ISP_FIFO6_SINK_REG, ISP_FIFO6_SINK_BIT); - stall->vamem1 = - !isp_ctrl_getbit(ID, ISP_VAMEM1_SINK_REG, ISP_VAMEM1_SINK_BIT); - stall->vamem2 = - !isp_ctrl_getbit(ID, ISP_VAMEM2_SINK_REG, ISP_VAMEM2_SINK_BIT); - stall->vamem3 = - !isp_ctrl_getbit(ID, ISP_VAMEM3_SINK_REG, ISP_VAMEM3_SINK_BIT); - stall->hmem = - !isp_ctrl_getbit(ID, ISP_HMEM_SINK_REG, ISP_HMEM_SINK_BIT); - /* - stall->icache_master = - !isp_ctrl_getbit(ID, ISP_ICACHE_MT_SINK_REG, - ISP_ICACHE_MT_SINK_BIT); - */ - return; -} - /* ISP functions to control the ISP state from the host, even in crun. */ /* Inspect readiness of an ISP indexed by ID */ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/isp_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/isp_local.h index 4dbec4063b3d5..fb98696cc44d1 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/isp_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/isp_local.h @@ -22,35 +22,4 @@ #define HIVE_ISP_VMEM_MASK ((1U << ISP_VMEM_ELEMBITS) - 1) -typedef struct isp_state_s isp_state_t; -typedef struct isp_stall_s isp_stall_t; - -struct isp_state_s { - int pc; - int status_register; - bool is_broken; - bool is_idle; - bool is_sleeping; - bool is_stalling; -}; - -struct isp_stall_s { - bool fifo0; - bool fifo1; - bool fifo2; - bool fifo3; - bool fifo4; - bool fifo5; - bool fifo6; - bool stat_ctrl; - bool dmem; - bool vmem; - bool vamem1; - bool vamem2; - bool vamem3; - bool hmem; - bool pmem; - bool icache_master; -}; - #endif /* __ISP_LOCAL_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/sp.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/sp.c index aae18465b6ae2..3dc4d1289ea1b 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/sp.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/sp.c @@ -33,50 +33,3 @@ void cnd_sp_irq_enable( sp_ctrl_clearbit(ID, SP_IRQ_READY_REG, SP_IRQ_READY_BIT); } } - -void sp_get_state( - const sp_ID_t ID, - sp_state_t *state, - sp_stall_t *stall) -{ - hrt_data sc = sp_ctrl_load(ID, SP_SC_REG); - - assert(state); - assert(stall); - - state->pc = sp_ctrl_load(ID, SP_PC_REG); - state->status_register = sc; - state->is_broken = (sc & (1U << SP_BROKEN_BIT)) != 0; - state->is_idle = (sc & (1U << SP_IDLE_BIT)) != 0; - state->is_sleeping = (sc & (1U << SP_SLEEPING_BIT)) != 0; - state->is_stalling = (sc & (1U << SP_STALLING_BIT)) != 0; - stall->fifo0 = - !sp_ctrl_getbit(ID, SP_FIFO0_SINK_REG, SP_FIFO0_SINK_BIT); - stall->fifo1 = - !sp_ctrl_getbit(ID, SP_FIFO1_SINK_REG, SP_FIFO1_SINK_BIT); - stall->fifo2 = - !sp_ctrl_getbit(ID, SP_FIFO2_SINK_REG, SP_FIFO2_SINK_BIT); - stall->fifo3 = - !sp_ctrl_getbit(ID, SP_FIFO3_SINK_REG, SP_FIFO3_SINK_BIT); - stall->fifo4 = - !sp_ctrl_getbit(ID, SP_FIFO4_SINK_REG, SP_FIFO4_SINK_BIT); - stall->fifo5 = - !sp_ctrl_getbit(ID, SP_FIFO5_SINK_REG, SP_FIFO5_SINK_BIT); - stall->fifo6 = - !sp_ctrl_getbit(ID, SP_FIFO6_SINK_REG, SP_FIFO6_SINK_BIT); - stall->fifo7 = - !sp_ctrl_getbit(ID, SP_FIFO7_SINK_REG, SP_FIFO7_SINK_BIT); - stall->fifo8 = - !sp_ctrl_getbit(ID, SP_FIFO8_SINK_REG, SP_FIFO8_SINK_BIT); - stall->fifo9 = - !sp_ctrl_getbit(ID, SP_FIFO9_SINK_REG, SP_FIFO9_SINK_BIT); - stall->fifoa = - !sp_ctrl_getbit(ID, SP_FIFOA_SINK_REG, SP_FIFOA_SINK_BIT); - stall->dmem = - !sp_ctrl_getbit(ID, SP_DMEM_SINK_REG, SP_DMEM_SINK_BIT); - stall->control_master = - !sp_ctrl_getbit(ID, SP_CTRL_MT_SINK_REG, SP_CTRL_MT_SINK_BIT); - stall->icache_master = - !sp_ctrl_getbit(ID, SP_ICACHE_MT_SINK_REG, - SP_ICACHE_MT_SINK_BIT); -} diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/sp_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/sp_local.h index 2956c7023b334..e22d25a902f40 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/sp_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/sp_local.h @@ -19,32 +19,6 @@ #include #include "sp_global.h" -struct sp_state_s { - int pc; - int status_register; - bool is_broken; - bool is_idle; - bool is_sleeping; - bool is_stalling; -}; - -struct sp_stall_s { - bool fifo0; - bool fifo1; - bool fifo2; - bool fifo3; - bool fifo4; - bool fifo5; - bool fifo6; - bool fifo7; - bool fifo8; - bool fifo9; - bool fifoa; - bool dmem; - bool control_master; - bool icache_master; -}; - #define sp_address_of(var) (HIVE_ADDR_ ## var) /* diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/dma_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/dma_public.h index a23cbc9a2129a..6fed47f045945 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/dma_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/dma_public.h @@ -18,19 +18,6 @@ #include "system_local.h" -typedef struct dma_state_s dma_state_t; - -/*! Read the control registers of DMA[ID] - - \param ID[in] DMA identifier - \param state[out] input formatter state structure - - \return none, state = DMA[ID].state - */ -void dma_get_state( - const dma_ID_t ID, - dma_state_t *state); - /*! Write to a control register of DMA[ID] \param ID[in] DMA identifier diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/irq_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/irq_public.h index d335e7b0a76e5..43787ab64078a 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/irq_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/irq_public.h @@ -19,16 +19,6 @@ #include #include "system_local.h" -/*! Read the control registers of IRQ[ID] - - \param ID[in] IRQ identifier - \param state[out] irq controller state structure - - \return none, state = IRQ[ID].state - */ -void irq_controller_get_state(const irq_ID_t ID, - struct irq_controller_state *state); - /*! Write to a control register of IRQ[ID] \param ID[in] IRQ identifier diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isp_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isp_public.h index a8ff75c639e52..34dd7f912df60 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isp_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isp_public.h @@ -30,19 +30,6 @@ void cnd_isp_irq_enable( const isp_ID_t ID, const bool cnd); -/*! Read the state of cell ISP[ID] - - \param ID[in] ISP identifier - \param state[out] isp state structure - \param stall[out] isp stall conditions - - \return none, state = ISP[ID].state, stall = ISP[ID].stall - */ -void isp_get_state( - const isp_ID_t ID, - isp_state_t *state, - isp_stall_t *stall); - /*! Write to the status and control register of ISP[ID] \param ID[in] ISP identifier diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/sp_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/sp_public.h index b0b7f2e278546..e9166535ce099 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/sp_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/sp_public.h @@ -19,9 +19,6 @@ #include #include "system_local.h" -typedef struct sp_state_s sp_state_t; -typedef struct sp_stall_s sp_stall_t; - /*! Enable or disable the program complete irq signal of SP[ID] \param ID[in] SP identifier @@ -33,19 +30,6 @@ void cnd_sp_irq_enable( const sp_ID_t ID, const bool cnd); -/*! Read the state of cell SP[ID] - - \param ID[in] SP identifier - \param state[out] sp state structure - \param stall[out] isp stall conditions - - \return none, state = SP[ID].state, stall = SP[ID].stall - */ -void sp_get_state( - const sp_ID_t ID, - sp_state_t *state, - sp_stall_t *stall); - /*! Write to the status and control register of SP[ID] \param ID[in] SP identifier diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h index 6319d6449f201..f9b9c3ae50aa7 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h @@ -163,10 +163,6 @@ struct input_system_cfg2400_s { #define _HRT_CSS_RECEIVER_DATA_TIMEOUT_IDX _HRT_CSS_RECEIVER_2400_CSI2_DATA_TIMEOUT_IDX #define _HRT_CSS_RECEIVER_DATA_TIMEOUT_BITS _HRT_CSS_RECEIVER_2400_CSI2_DATA_TIMEOUT_BITS -typedef struct capture_unit_state_s capture_unit_state_t; -typedef struct acquisition_unit_state_s acquisition_unit_state_t; -typedef struct ctrl_unit_state_s ctrl_unit_state_t; - typedef enum { MIPI_FORMAT_2400_RGB888 = 0, MIPI_FORMAT_2400_RGB555, @@ -244,113 +240,4 @@ static const hrt_address __maybe_unused SUB_SYSTEM_OFFSET[N_SUB_SYSTEM_ID] = { 0x0000C000UL }; -struct capture_unit_state_s { - int Packet_Length; - int Received_Length; - int Received_Short_Packets; - int Received_Long_Packets; - int Last_Command; - int Next_Command; - int Last_Acknowledge; - int Next_Acknowledge; - int FSM_State_Info; - int StartMode; - int Start_Addr; - int Mem_Region_Size; - int Num_Mem_Regions; - /* int Init; write-only registers - int Start; - int Stop; */ -}; - -struct acquisition_unit_state_s { - /* int Init; write-only register */ - int Received_Short_Packets; - int Received_Long_Packets; - int Last_Command; - int Next_Command; - int Last_Acknowledge; - int Next_Acknowledge; - int FSM_State_Info; - int Int_Cntr_Info; - int Start_Addr; - int Mem_Region_Size; - int Num_Mem_Regions; -}; - -struct ctrl_unit_state_s { - int last_cmd; - int next_cmd; - int last_ack; - int next_ack; - int top_fsm_state; - int captA_fsm_state; - int captB_fsm_state; - int captC_fsm_state; - int acq_fsm_state; - int captA_start_addr; - int captB_start_addr; - int captC_start_addr; - int captA_mem_region_size; - int captB_mem_region_size; - int captC_mem_region_size; - int captA_num_mem_regions; - int captB_num_mem_regions; - int captC_num_mem_regions; - int acq_start_addr; - int acq_mem_region_size; - int acq_num_mem_regions; - /* int ctrl_init; write only register */ - int capt_reserve_one_mem_region; -}; - -struct mipi_port_state_s { - int device_ready; - int irq_status; - int irq_enable; - u32 timeout_count; - u16 init_count; - u16 raw16_18; - u32 sync_count; /*4 x uint8_t */ - u32 rx_count; /*4 x uint8_t */ - u8 lane_sync_count[MIPI_4LANE_CFG]; - u8 lane_rx_count[MIPI_4LANE_CFG]; -}; - -struct rx_channel_state_s { - u32 comp_scheme0; - u32 comp_scheme1; - mipi_predictor_t pred[N_MIPI_FORMAT_CUSTOM]; - mipi_compressor_t comp[N_MIPI_FORMAT_CUSTOM]; -}; - -struct receiver_state_s { - u8 fs_to_ls_delay; - u8 ls_to_data_delay; - u8 data_to_le_delay; - u8 le_to_fe_delay; - u8 fe_to_fs_delay; - u8 le_to_fs_delay; - bool is_two_ppc; - int backend_rst; - u16 raw18; - bool force_raw8; - u16 raw16; - struct mipi_port_state_s mipi_port_state[N_MIPI_PORT_ID]; - struct rx_channel_state_s rx_channel_state[N_RX_CHANNEL_ID]; - int be_gsp_acc_ovl; - int be_srst; - int be_is_two_ppc; - int be_comp_format0; - int be_comp_format1; - int be_comp_format2; - int be_comp_format3; - int be_sel; - int be_raw16_config; - int be_raw18_config; - int be_force_raw8; - int be_irq_status; - int be_irq_clear; -}; - #endif /* __INPUT_SYSTEM_LOCAL_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h index b1360eeb58df8..447c7c5c55a1f 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h @@ -18,34 +18,6 @@ #include -typedef struct receiver_state_s receiver_state_t; - -/*! Read the state of INPUT_SYSTEM[ID] - - \param ID[in] INPUT_SYSTEM identifier - \param state[out] input system state structure - - \return none, state = INPUT_SYSTEM[ID].state - */ - -/*! Read the state of RECEIVER[ID] - - \param ID[in] RECEIVER identifier - \param state[out] receiver state structure - - \return none, state = RECEIVER[ID].state - */ -void receiver_get_state( - const rx_ID_t ID, - receiver_state_t *state); - -/*! Flag whether a MIPI format is YUV420 - - \param mipi_format[in] MIPI format - - \return mipi_format == YUV420 - */ - /*! Set compression parameters for cfg[cfg_ID] of RECEIVER[ID] \param ID[in] RECEIVER identifier diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h index b74ab50ea01e3..e9a09117e5e51 100644 --- a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h +++ b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h @@ -154,18 +154,6 @@ void ia_css_debug_set_dtrace_level( */ unsigned int ia_css_debug_get_dtrace_level(void); -/*! @brief Dump isp hardware state. - * Dumps the isp hardware state to tracing output. - * @return None - */ -void ia_css_debug_dump_isp_state(void); - -/*! @brief Dump sp hardware state. - * Dumps the sp hardware state to tracing output. - * @return None - */ -void ia_css_debug_dump_sp_state(void); - /* ISP2401 */ /*! @brief Dump GAC hardware state. * Dumps the GAC ACB hardware registers. may be useful for @@ -174,25 +162,12 @@ void ia_css_debug_dump_sp_state(void); */ void ia_css_debug_dump_gac_state(void); -/*! @brief Dump dma controller state. - * Dumps the dma controller state to tracing output. - * @return None - */ -void ia_css_debug_dump_dma_state(void); - /*! @brief Dump internal sp software state. * Dumps the sp software state to tracing output. * @return None */ void ia_css_debug_dump_sp_sw_debug_info(void); -/*! @brief Dump all related hardware state to the trace output - * @param[in] context String to identify context in output. - * @return None - */ -void ia_css_debug_dump_debug_info( - const char *context); - #if SP_DEBUG != SP_DEBUG_NONE void ia_css_debug_print_sp_debug_state( const struct sh_css_sp_debug_state *state); @@ -207,24 +182,6 @@ void ia_css_debug_binary_print( void ia_css_debug_sp_dump_mipi_fifo_high_water(void); -/*! @brief Dump isp gdc fifo state to the trace output - * Dumps the isp gdc fifo state to tracing output. - * @return None - */ -void ia_css_debug_dump_isp_gdc_fifo_state(void); - -/*! @brief Dump dma isp fifo state - * Dumps the dma isp fifo state to tracing output. - * @return None - */ -void ia_css_debug_dump_dma_isp_fifo_state(void); - -/*! @brief Dump dma sp fifo state - * Dumps the dma sp fifo state to tracing output. - * @return None - */ -void ia_css_debug_dump_dma_sp_fifo_state(void); - /*! \brief Dump pif A isp fifo state * Dumps the primary input formatter state to tracing output. * @return None @@ -243,24 +200,12 @@ void ia_css_debug_dump_pif_b_isp_fifo_state(void); */ void ia_css_debug_dump_str2mem_sp_fifo_state(void); -/*! @brief Dump isp sp fifo state - * Dumps the isp sp fifo state to tracing output. - * @return None - */ -void ia_css_debug_dump_isp_sp_fifo_state(void); - /*! @brief Dump all fifo state info to the output * Dumps all fifo state to tracing output. * @return None */ void ia_css_debug_dump_all_fifo_state(void); -/*! @brief Dump the rx state to the output - * Dumps the rx state to tracing output. - * @return None - */ -void ia_css_debug_dump_rx_state(void); - /*! @brief Dump the frame info to the trace output * Dumps the frame info to tracing output. * @param[in] frame pointer to struct ia_css_frame @@ -294,12 +239,6 @@ void ia_css_debug_wake_up_sp(void); void ia_css_debug_dump_isp_params(struct ia_css_stream *stream, unsigned int enable); -/*! @brief Function to dump some sp performance counters. - * Dump sp performance counters, currently input system errors. - * @return None - */ -void ia_css_debug_dump_perf_counters(void); - void ia_css_debug_dump_isp_binary(void); void sh_css_dump_sp_raw_copy_linecount(bool reduced); @@ -382,12 +321,6 @@ void ia_css_debug_dump_stream_config( const struct ia_css_stream_config *config, int num_pipes); -/*! @brief Dump the state of the SP tagger - * Dumps the internal state of the SP tagger - * @return None - */ -void ia_css_debug_tagger_state(void); - /** * @brief Initialize the debug mode. * diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c index d40ed9c60f1dc..321485f75fb5f 100644 --- a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c +++ b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c @@ -308,136 +308,6 @@ static const char *debug_frame_format2str(const enum ia_css_frame_format } } -static void debug_print_sp_state(const sp_state_t *state, const char *cell) -{ - assert(cell); - assert(state); - - ia_css_debug_dtrace(2, "%s state:\n", cell); - ia_css_debug_dtrace(2, "\t%-32s: 0x%X\n", "PC", state->pc); - ia_css_debug_dtrace(2, "\t%-32s: 0x%X\n", "Status register", - state->status_register); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "Is broken", state->is_broken); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "Is idle", state->is_idle); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "Is sleeping", - state->is_sleeping); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "Is stalling", - state->is_stalling); - return; -} - -static void debug_print_isp_state(const isp_state_t *state, const char *cell) -{ - assert(state); - assert(cell); - - ia_css_debug_dtrace(2, "%s state:\n", cell); - ia_css_debug_dtrace(2, "\t%-32s: 0x%X\n", "PC", state->pc); - ia_css_debug_dtrace(2, "\t%-32s: 0x%X\n", "Status register", - state->status_register); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "Is broken", state->is_broken); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "Is idle", state->is_idle); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "Is sleeping", - state->is_sleeping); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "Is stalling", - state->is_stalling); - return; -} - -void ia_css_debug_dump_isp_state(void) -{ - isp_state_t state; - isp_stall_t stall; - - isp_get_state(ISP0_ID, &state, &stall); - - debug_print_isp_state(&state, "ISP"); - - if (state.is_stalling) { - if (!IS_ISP2401) { - ia_css_debug_dtrace(2, "\t%-32s: %d\n", - "[0] if_prim_a_FIFO stalled", stall.fifo0); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", - "[1] if_prim_b_FIFO stalled", stall.fifo1); - } - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "[2] dma_FIFO stalled", - stall.fifo2); - - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "[3] gdc0_FIFO stalled", - stall.fifo3); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "[4] gdc1_FIFO stalled", - stall.fifo4); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "[5] gpio_FIFO stalled", - stall.fifo5); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "[6] sp_FIFO stalled", - stall.fifo6); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", - "status & control stalled", - stall.stat_ctrl); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "dmem stalled", - stall.dmem); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "vmem stalled", - stall.vmem); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "vamem1 stalled", - stall.vamem1); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "vamem2 stalled", - stall.vamem2); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "vamem3 stalled", - stall.vamem3); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "hmem stalled", - stall.hmem); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "pmem stalled", - stall.pmem); - } - return; -} - -void ia_css_debug_dump_sp_state(void) -{ - sp_state_t state; - sp_stall_t stall; - - sp_get_state(SP0_ID, &state, &stall); - debug_print_sp_state(&state, "SP"); - if (state.is_stalling) { - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "isys_FIFO stalled", - stall.fifo0); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "if_sec_FIFO stalled", - stall.fifo1); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", - "str_to_mem_FIFO stalled", stall.fifo2); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "dma_FIFO stalled", - stall.fifo3); - if (!IS_ISP2401) - ia_css_debug_dtrace(2, "\t%-32s: %d\n", - "if_prim_a_FIFO stalled", stall.fifo4); - - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "isp_FIFO stalled", - stall.fifo5); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "gp_FIFO stalled", - stall.fifo6); - if (!IS_ISP2401) - ia_css_debug_dtrace(2, "\t%-32s: %d\n", - "if_prim_b_FIFO stalled", stall.fifo7); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "gdc0_FIFO stalled", - stall.fifo8); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "gdc1_FIFO stalled", - stall.fifo9); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "irq FIFO stalled", - stall.fifoa); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "dmem stalled", - stall.dmem); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", - "control master stalled", - stall.control_master); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", - "i-cache master stalled", - stall.icache_master); - } - ia_css_debug_dump_trace(); - return; -} - static void debug_print_fifo_channel_state(const fifo_channel_state_t *state, const char *descr) { @@ -492,634 +362,6 @@ void ia_css_debug_dump_str2mem_sp_fifo_state(void) debug_print_fifo_channel_state(&sp_to_s2m, "SP to stream-to-memory"); } -#ifndef ISP2401 -static void debug_print_if_state(input_formatter_state_t *state, const char *id) -{ - unsigned int val; - - const char *st_vsync_active_low = - (state->vsync_active_low ? "low" : "high"); - const char *st_hsync_active_low = - (state->hsync_active_low ? "low" : "high"); - - const char *fsm_sync_status_str = "unknown"; - const char *fsm_crop_status_str = "unknown"; - const char *fsm_padding_status_str = "unknown"; - - int st_stline = state->start_line; - int st_stcol = state->start_column; - int st_crpht = state->cropped_height; - int st_crpwd = state->cropped_width; - int st_verdcm = state->ver_decimation; - int st_hordcm = state->hor_decimation; - int st_ver_deinterleaving = state->ver_deinterleaving; - int st_hor_deinterleaving = state->hor_deinterleaving; - int st_leftpd = state->left_padding; - int st_eoloff = state->eol_offset; - int st_vmstartaddr = state->vmem_start_address; - int st_vmendaddr = state->vmem_end_address; - int st_vmincr = state->vmem_increment; - int st_yuv420 = state->is_yuv420; - int st_allow_fifo_overflow = state->allow_fifo_overflow; - int st_block_fifo_when_no_req = state->block_fifo_when_no_req; - - assert(state); - ia_css_debug_dtrace(2, "InputFormatter State (%s):\n", id); - - ia_css_debug_dtrace(2, "\tConfiguration:\n"); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Start line", st_stline); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Start column", st_stcol); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Cropped height", st_crpht); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Cropped width", st_crpwd); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Ver decimation", st_verdcm); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Hor decimation", st_hordcm); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Ver deinterleaving", st_ver_deinterleaving); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Hor deinterleaving", st_hor_deinterleaving); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Left padding", st_leftpd); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "EOL offset (bytes)", st_eoloff); - ia_css_debug_dtrace(2, "\t\t%-32s: 0x%06X\n", - "VMEM start address", st_vmstartaddr); - ia_css_debug_dtrace(2, "\t\t%-32s: 0x%06X\n", - "VMEM end address", st_vmendaddr); - ia_css_debug_dtrace(2, "\t\t%-32s: 0x%06X\n", - "VMEM increment", st_vmincr); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "YUV 420 format", st_yuv420); - ia_css_debug_dtrace(2, "\t\t%-32s: Active %s\n", - "Vsync", st_vsync_active_low); - ia_css_debug_dtrace(2, "\t\t%-32s: Active %s\n", - "Hsync", st_hsync_active_low); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Allow FIFO overflow", st_allow_fifo_overflow); - /* Flag that tells whether the IF gives backpressure on frames */ - /* - * FYI, this is only on the frame request (indicate), when the IF has - * synch'd on a frame it will always give back pressure - */ - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "Block when no request", st_block_fifo_when_no_req); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "IF_BLOCKED_FIFO_NO_REQ_ADDRESS", - input_formatter_reg_load(INPUT_FORMATTER0_ID, - HIVE_IF_BLOCK_FIFO_NO_REQ_ADDRESS) - ); - - ia_css_debug_dtrace(2, "\t%-32s:\n", "InputSwitch State"); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "_REG_GP_IFMT_input_switch_lut_reg0", - gp_device_reg_load(GP_DEVICE0_ID, - _REG_GP_IFMT_input_switch_lut_reg0)); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "_REG_GP_IFMT_input_switch_lut_reg1", - gp_device_reg_load(GP_DEVICE0_ID, - _REG_GP_IFMT_input_switch_lut_reg1)); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "_REG_GP_IFMT_input_switch_lut_reg2", - gp_device_reg_load(GP_DEVICE0_ID, - _REG_GP_IFMT_input_switch_lut_reg2)); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "_REG_GP_IFMT_input_switch_lut_reg3", - gp_device_reg_load(GP_DEVICE0_ID, - _REG_GP_IFMT_input_switch_lut_reg3)); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "_REG_GP_IFMT_input_switch_lut_reg4", - gp_device_reg_load(GP_DEVICE0_ID, - _REG_GP_IFMT_input_switch_lut_reg4)); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "_REG_GP_IFMT_input_switch_lut_reg5", - gp_device_reg_load(GP_DEVICE0_ID, - _REG_GP_IFMT_input_switch_lut_reg5)); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "_REG_GP_IFMT_input_switch_lut_reg6", - gp_device_reg_load(GP_DEVICE0_ID, - _REG_GP_IFMT_input_switch_lut_reg6)); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "_REG_GP_IFMT_input_switch_lut_reg7", - gp_device_reg_load(GP_DEVICE0_ID, - _REG_GP_IFMT_input_switch_lut_reg7)); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "_REG_GP_IFMT_input_switch_fsync_lut", - gp_device_reg_load(GP_DEVICE0_ID, - _REG_GP_IFMT_input_switch_fsync_lut)); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "_REG_GP_IFMT_srst", - gp_device_reg_load(GP_DEVICE0_ID, - _REG_GP_IFMT_srst)); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "_REG_GP_IFMT_slv_reg_srst", - gp_device_reg_load(GP_DEVICE0_ID, - _REG_GP_IFMT_slv_reg_srst)); - - ia_css_debug_dtrace(2, "\tFSM Status:\n"); - - val = state->fsm_sync_status; - - if (val > 7) - fsm_sync_status_str = "ERROR"; - - switch (val & 0x7) { - case 0: - fsm_sync_status_str = "idle"; - break; - case 1: - fsm_sync_status_str = "request frame"; - break; - case 2: - fsm_sync_status_str = "request lines"; - break; - case 3: - fsm_sync_status_str = "request vectors"; - break; - case 4: - fsm_sync_status_str = "send acknowledge"; - break; - default: - fsm_sync_status_str = "unknown"; - break; - } - - ia_css_debug_dtrace(2, "\t\t%-32s: (0x%X: %s)\n", - "FSM Synchronization Status", val, - fsm_sync_status_str); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "FSM Synchronization Counter", - state->fsm_sync_counter); - - val = state->fsm_crop_status; - - if (val > 7) - fsm_crop_status_str = "ERROR"; - - switch (val & 0x7) { - case 0: - fsm_crop_status_str = "idle"; - break; - case 1: - fsm_crop_status_str = "wait line"; - break; - case 2: - fsm_crop_status_str = "crop line"; - break; - case 3: - fsm_crop_status_str = "crop pixel"; - break; - case 4: - fsm_crop_status_str = "pass pixel"; - break; - case 5: - fsm_crop_status_str = "pass line"; - break; - case 6: - fsm_crop_status_str = "lost line"; - break; - default: - fsm_crop_status_str = "unknown"; - break; - } - ia_css_debug_dtrace(2, "\t\t%-32s: (0x%X: %s)\n", - "FSM Crop Status", val, fsm_crop_status_str); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "FSM Crop Line Counter", - state->fsm_crop_line_counter); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "FSM Crop Pixel Counter", - state->fsm_crop_pixel_counter); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "FSM Deinterleaving idx buffer", - state->fsm_deinterleaving_index); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "FSM H decimation counter", - state->fsm_dec_h_counter); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "FSM V decimation counter", - state->fsm_dec_v_counter); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "FSM block V decimation counter", - state->fsm_dec_block_v_counter); - - val = state->fsm_padding_status; - - if (val > 7) - fsm_padding_status_str = "ERROR"; - - switch (val & 0x7) { - case 0: - fsm_padding_status_str = "idle"; - break; - case 1: - fsm_padding_status_str = "left pad"; - break; - case 2: - fsm_padding_status_str = "write"; - break; - case 3: - fsm_padding_status_str = "right pad"; - break; - case 4: - fsm_padding_status_str = "send end of line"; - break; - default: - fsm_padding_status_str = "unknown"; - break; - } - - ia_css_debug_dtrace(2, "\t\t%-32s: (0x%X: %s)\n", "FSM Padding Status", - val, fsm_padding_status_str); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "FSM Padding element idx counter", - state->fsm_padding_elem_counter); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Vector support error", - state->fsm_vector_support_error); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Vector support buf full", - state->fsm_vector_buffer_full); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Vector support", - state->vector_support); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Fifo sensor data lost", - state->sensor_data_lost); -} - -static void debug_print_if_bin_state(input_formatter_bin_state_t *state) -{ - ia_css_debug_dtrace(2, "Stream-to-memory state:\n"); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "reset", state->reset); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "input endianness", - state->input_endianness); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "output endianness", - state->output_endianness); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "bitswap", state->bitswap); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "block_synch", - state->block_synch); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "packet_synch", - state->packet_synch); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "readpostwrite_sync", - state->readpostwrite_synch); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "is_2ppc", state->is_2ppc); - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "en_status_update", - state->en_status_update); -} - -static void ia_css_debug_dump_if_state(void) -{ - input_formatter_state_t if_state; - input_formatter_bin_state_t if_bin_state; - - input_formatter_get_state(INPUT_FORMATTER0_ID, &if_state); - debug_print_if_state(&if_state, "Primary IF A"); - ia_css_debug_dump_pif_a_isp_fifo_state(); - - input_formatter_get_state(INPUT_FORMATTER1_ID, &if_state); - debug_print_if_state(&if_state, "Primary IF B"); - ia_css_debug_dump_pif_b_isp_fifo_state(); - - input_formatter_bin_get_state(INPUT_FORMATTER3_ID, &if_bin_state); - debug_print_if_bin_state(&if_bin_state); - ia_css_debug_dump_str2mem_sp_fifo_state(); -} -#endif - -void ia_css_debug_dump_dma_state(void) -{ - /* note: the var below is made static as it is quite large; - if it is not static it ends up on the stack which could - cause issues for drivers - */ - static dma_state_t state; - int i, ch_id; - - const char *fsm_cmd_st_lbl = "FSM Command flag state"; - const char *fsm_ctl_st_lbl = "FSM Control flag state"; - const char *fsm_ctl_state = NULL; - const char *fsm_ctl_flag = NULL; - const char *fsm_pack_st = NULL; - const char *fsm_read_st = NULL; - const char *fsm_write_st = NULL; - char last_cmd_str[64]; - - dma_get_state(DMA0_ID, &state); - /* Print header for DMA dump status */ - ia_css_debug_dtrace(2, "DMA dump status:\n"); - - /* Print FSM command flag state */ - if (state.fsm_command_idle) - ia_css_debug_dtrace(2, "\t%-32s: %s\n", fsm_cmd_st_lbl, "IDLE"); - if (state.fsm_command_run) - ia_css_debug_dtrace(2, "\t%-32s: %s\n", fsm_cmd_st_lbl, "RUN"); - if (state.fsm_command_stalling) - ia_css_debug_dtrace(2, "\t%-32s: %s\n", fsm_cmd_st_lbl, - "STALL"); - if (state.fsm_command_error) - ia_css_debug_dtrace(2, "\t%-32s: %s\n", fsm_cmd_st_lbl, - "ERROR"); - - /* Print last command along with the channel */ - ch_id = state.last_command_channel; - - switch (state.last_command) { - case DMA_COMMAND_READ: - snprintf(last_cmd_str, 64, - "Read 2D Block [Channel: %d]", ch_id); - break; - case DMA_COMMAND_WRITE: - snprintf(last_cmd_str, 64, - "Write 2D Block [Channel: %d]", ch_id); - break; - case DMA_COMMAND_SET_CHANNEL: - snprintf(last_cmd_str, 64, "Set Channel [Channel: %d]", ch_id); - break; - case DMA_COMMAND_SET_PARAM: - snprintf(last_cmd_str, 64, - "Set Param: %d [Channel: %d]", - state.last_command_param, ch_id); - break; - case DMA_COMMAND_READ_SPECIFIC: - snprintf(last_cmd_str, 64, - "Read Specific 2D Block [Channel: %d]", ch_id); - break; - case DMA_COMMAND_WRITE_SPECIFIC: - snprintf(last_cmd_str, 64, - "Write Specific 2D Block [Channel: %d]", ch_id); - break; - case DMA_COMMAND_INIT: - snprintf(last_cmd_str, 64, - "Init 2D Block on Device A [Channel: %d]", ch_id); - break; - case DMA_COMMAND_INIT_SPECIFIC: - snprintf(last_cmd_str, 64, - "Init Specific 2D Block [Channel: %d]", ch_id); - break; - case DMA_COMMAND_RST: - snprintf(last_cmd_str, 64, "DMA SW Reset"); - break; - case N_DMA_COMMANDS: - snprintf(last_cmd_str, 64, "UNKNOWN"); - break; - default: - snprintf(last_cmd_str, 64, - "unknown [Channel: %d]", ch_id); - break; - } - ia_css_debug_dtrace(2, "\t%-32s: (0x%X : %s)\n", - "last command received", state.last_command, - last_cmd_str); - - /* Print DMA registers */ - ia_css_debug_dtrace(2, "\t%-32s\n", - "DMA registers, connection group 0"); - ia_css_debug_dtrace(2, "\t\t%-32s: 0x%X\n", "Cmd Fifo Command", - state.current_command); - ia_css_debug_dtrace(2, "\t\t%-32s: 0x%X\n", "Cmd Fifo Address A", - state.current_addr_a); - ia_css_debug_dtrace(2, "\t\t%-32s: 0x%X\n", "Cmd Fifo Address B", - state.current_addr_b); - - if (state.fsm_ctrl_idle) - fsm_ctl_flag = "IDLE"; - else if (state.fsm_ctrl_run) - fsm_ctl_flag = "RUN"; - else if (state.fsm_ctrl_stalling) - fsm_ctl_flag = "STAL"; - else if (state.fsm_ctrl_error) - fsm_ctl_flag = "ERROR"; - else - fsm_ctl_flag = "UNKNOWN"; - - switch (state.fsm_ctrl_state) { - case DMA_CTRL_STATE_IDLE: - fsm_ctl_state = "Idle state"; - break; - case DMA_CTRL_STATE_REQ_RCV: - fsm_ctl_state = "Req Rcv state"; - break; - case DMA_CTRL_STATE_RCV: - fsm_ctl_state = "Rcv state"; - break; - case DMA_CTRL_STATE_RCV_REQ: - fsm_ctl_state = "Rcv Req state"; - break; - case DMA_CTRL_STATE_INIT: - fsm_ctl_state = "Init state"; - break; - case N_DMA_CTRL_STATES: - fsm_ctl_state = "Unknown"; - break; - } - - ia_css_debug_dtrace(2, "\t\t%-32s: %s -> %s\n", fsm_ctl_st_lbl, - fsm_ctl_flag, fsm_ctl_state); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl source dev", - state.fsm_ctrl_source_dev); - ia_css_debug_dtrace(2, "\t\t%-32s: 0x%X\n", "FSM Ctrl source addr", - state.fsm_ctrl_source_addr); - ia_css_debug_dtrace(2, "\t\t%-32s: 0x%X\n", "FSM Ctrl source stride", - state.fsm_ctrl_source_stride); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl source width", - state.fsm_ctrl_source_width); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl source height", - state.fsm_ctrl_source_height); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl pack source dev", - state.fsm_ctrl_pack_source_dev); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl pack dest dev", - state.fsm_ctrl_pack_dest_dev); - ia_css_debug_dtrace(2, "\t\t%-32s: 0x%X\n", "FSM Ctrl dest addr", - state.fsm_ctrl_dest_addr); - ia_css_debug_dtrace(2, "\t\t%-32s: 0x%X\n", "FSM Ctrl dest stride", - state.fsm_ctrl_dest_stride); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl pack source width", - state.fsm_ctrl_pack_source_width); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl pack dest height", - state.fsm_ctrl_pack_dest_height); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl pack dest width", - state.fsm_ctrl_pack_dest_width); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl pack source elems", - state.fsm_ctrl_pack_source_elems); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl pack dest elems", - state.fsm_ctrl_pack_dest_elems); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl pack extension", - state.fsm_ctrl_pack_extension); - - if (state.pack_idle) - fsm_pack_st = "IDLE"; - if (state.pack_run) - fsm_pack_st = "RUN"; - if (state.pack_stalling) - fsm_pack_st = "STALL"; - if (state.pack_error) - fsm_pack_st = "ERROR"; - - ia_css_debug_dtrace(2, "\t\t%-32s: %s\n", "FSM Pack flag state", - fsm_pack_st); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Pack cnt height", - state.pack_cnt_height); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Pack src cnt width", - state.pack_src_cnt_width); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Pack dest cnt width", - state.pack_dest_cnt_width); - - if (state.read_state == DMA_RW_STATE_IDLE) - fsm_read_st = "Idle state"; - if (state.read_state == DMA_RW_STATE_REQ) - fsm_read_st = "Req state"; - if (state.read_state == DMA_RW_STATE_NEXT_LINE) - fsm_read_st = "Next line"; - if (state.read_state == DMA_RW_STATE_UNLOCK_CHANNEL) - fsm_read_st = "Unlock channel"; - - ia_css_debug_dtrace(2, "\t\t%-32s: %s\n", "FSM Read state", - fsm_read_st); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Read cnt height", - state.read_cnt_height); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Read cnt width", - state.read_cnt_width); - - if (state.write_state == DMA_RW_STATE_IDLE) - fsm_write_st = "Idle state"; - if (state.write_state == DMA_RW_STATE_REQ) - fsm_write_st = "Req state"; - if (state.write_state == DMA_RW_STATE_NEXT_LINE) - fsm_write_st = "Next line"; - if (state.write_state == DMA_RW_STATE_UNLOCK_CHANNEL) - fsm_write_st = "Unlock channel"; - - ia_css_debug_dtrace(2, "\t\t%-32s: %s\n", "FSM Write state", - fsm_write_st); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Write height", - state.write_height); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Write width", - state.write_width); - - for (i = 0; i < HIVE_ISP_NUM_DMA_CONNS; i++) { - dma_port_state_t *port = &state.port_states[i]; - - ia_css_debug_dtrace(2, "\tDMA device interface %d\n", i); - ia_css_debug_dtrace(2, "\t\tDMA internal side state\n"); - ia_css_debug_dtrace(2, - "\t\t\tCS:%d - We_n:%d - Run:%d - Ack:%d\n", - port->req_cs, port->req_we_n, port->req_run, - port->req_ack); - ia_css_debug_dtrace(2, "\t\tMaster Output side state\n"); - ia_css_debug_dtrace(2, - "\t\t\tCS:%d - We_n:%d - Run:%d - Ack:%d\n", - port->send_cs, port->send_we_n, - port->send_run, port->send_ack); - ia_css_debug_dtrace(2, "\t\tFifo state\n"); - if (port->fifo_state == DMA_FIFO_STATE_WILL_BE_FULL) - ia_css_debug_dtrace(2, "\t\t\tFiFo will be full\n"); - else if (port->fifo_state == DMA_FIFO_STATE_FULL) - ia_css_debug_dtrace(2, "\t\t\tFifo Full\n"); - else if (port->fifo_state == DMA_FIFO_STATE_EMPTY) - ia_css_debug_dtrace(2, "\t\t\tFifo Empty\n"); - else - ia_css_debug_dtrace(2, "\t\t\tFifo state unknown\n"); - - ia_css_debug_dtrace(2, "\t\tFifo counter %d\n\n", - port->fifo_counter); - } - - for (i = 0; i < HIVE_DMA_NUM_CHANNELS; i++) { - dma_channel_state_t *ch = &state.channel_states[i]; - - ia_css_debug_dtrace(2, "\t%-32s: %d\n", "DMA channel register", - i); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Connection", - ch->connection); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Sign extend", - ch->sign_extend); - ia_css_debug_dtrace(2, "\t\t%-32s: 0x%X\n", "Stride Dev A", - ch->stride_a); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Elems Dev A", - ch->elems_a); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Cropping Dev A", - ch->cropping_a); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Width Dev A", - ch->width_a); - ia_css_debug_dtrace(2, "\t\t%-32s: 0x%X\n", "Stride Dev B", - ch->stride_b); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Elems Dev B", - ch->elems_b); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Cropping Dev B", - ch->cropping_b); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Width Dev B", - ch->width_b); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Height", ch->height); - } - ia_css_debug_dtrace(2, "\n"); - return; -} - -void ia_css_debug_dump_dma_sp_fifo_state(void) -{ - fifo_channel_state_t dma_to_sp, sp_to_dma; - - fifo_channel_get_state(FIFO_MONITOR0_ID, - FIFO_CHANNEL_DMA0_TO_SP0, &dma_to_sp); - fifo_channel_get_state(FIFO_MONITOR0_ID, - FIFO_CHANNEL_SP0_TO_DMA0, &sp_to_dma); - debug_print_fifo_channel_state(&dma_to_sp, "DMA to SP"); - debug_print_fifo_channel_state(&sp_to_dma, "SP to DMA"); - return; -} - -void ia_css_debug_dump_dma_isp_fifo_state(void) -{ - fifo_channel_state_t dma_to_isp, isp_to_dma; - - fifo_channel_get_state(FIFO_MONITOR0_ID, - FIFO_CHANNEL_DMA0_TO_ISP0, &dma_to_isp); - fifo_channel_get_state(FIFO_MONITOR0_ID, - FIFO_CHANNEL_ISP0_TO_DMA0, &isp_to_dma); - debug_print_fifo_channel_state(&dma_to_isp, "DMA to ISP"); - debug_print_fifo_channel_state(&isp_to_dma, "ISP to DMA"); - return; -} - -void ia_css_debug_dump_isp_sp_fifo_state(void) -{ - fifo_channel_state_t sp_to_isp, isp_to_sp; - - fifo_channel_get_state(FIFO_MONITOR0_ID, - FIFO_CHANNEL_SP0_TO_ISP0, &sp_to_isp); - fifo_channel_get_state(FIFO_MONITOR0_ID, - FIFO_CHANNEL_ISP0_TO_SP0, &isp_to_sp); - debug_print_fifo_channel_state(&sp_to_isp, "SP to ISP"); - debug_print_fifo_channel_state(&isp_to_sp, "ISP to SP"); - return; -} - -void ia_css_debug_dump_isp_gdc_fifo_state(void) -{ - fifo_channel_state_t gdc_to_isp, isp_to_gdc; - - fifo_channel_get_state(FIFO_MONITOR0_ID, - FIFO_CHANNEL_GDC0_TO_ISP0, &gdc_to_isp); - fifo_channel_get_state(FIFO_MONITOR0_ID, - FIFO_CHANNEL_ISP0_TO_GDC0, &isp_to_gdc); - debug_print_fifo_channel_state(&gdc_to_isp, "GDC to ISP"); - debug_print_fifo_channel_state(&isp_to_gdc, "ISP to GDC"); - return; -} - void ia_css_debug_dump_all_fifo_state(void) { int i; @@ -1579,213 +821,6 @@ void ia_css_debug_print_sp_debug_state(const struct sh_css_sp_debug_state } #endif -#if !defined(ISP2401) -static void debug_print_rx_mipi_port_state(mipi_port_state_t *state) -{ - int i; - unsigned int bits, infos; - - assert(state); - - bits = state->irq_status; - infos = ia_css_isys_rx_translate_irq_infos(bits); - - ia_css_debug_dtrace(2, "\t\t%-32s: (irq reg = 0x%X)\n", - "receiver errors", bits); - - if (infos & IA_CSS_RX_IRQ_INFO_BUFFER_OVERRUN) - ia_css_debug_dtrace(2, "\t\t\tbuffer overrun\n"); - if (infos & IA_CSS_RX_IRQ_INFO_ERR_SOT) - ia_css_debug_dtrace(2, "\t\t\tstart-of-transmission error\n"); - if (infos & IA_CSS_RX_IRQ_INFO_ERR_SOT_SYNC) - ia_css_debug_dtrace(2, "\t\t\tstart-of-transmission sync error\n"); - if (infos & IA_CSS_RX_IRQ_INFO_ERR_CONTROL) - ia_css_debug_dtrace(2, "\t\t\tcontrol error\n"); - if (infos & IA_CSS_RX_IRQ_INFO_ERR_ECC_DOUBLE) - ia_css_debug_dtrace(2, "\t\t\t2 or more ECC errors\n"); - if (infos & IA_CSS_RX_IRQ_INFO_ERR_CRC) - ia_css_debug_dtrace(2, "\t\t\tCRC mismatch\n"); - if (infos & IA_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ID) - ia_css_debug_dtrace(2, "\t\t\tunknown error\n"); - if (infos & IA_CSS_RX_IRQ_INFO_ERR_FRAME_SYNC) - ia_css_debug_dtrace(2, "\t\t\tframe sync error\n"); - if (infos & IA_CSS_RX_IRQ_INFO_ERR_FRAME_DATA) - ia_css_debug_dtrace(2, "\t\t\tframe data error\n"); - if (infos & IA_CSS_RX_IRQ_INFO_ERR_DATA_TIMEOUT) - ia_css_debug_dtrace(2, "\t\t\tdata timeout\n"); - if (infos & IA_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ESC) - ia_css_debug_dtrace(2, "\t\t\tunknown escape command entry\n"); - if (infos & IA_CSS_RX_IRQ_INFO_ERR_LINE_SYNC) - ia_css_debug_dtrace(2, "\t\t\tline sync error\n"); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "device_ready", state->device_ready); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "irq_status", state->irq_status); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "irq_enable", state->irq_enable); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "timeout_count", state->timeout_count); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "init_count", state->init_count); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "raw16_18", state->raw16_18); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "sync_count", state->sync_count); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "rx_count", state->rx_count); - - for (i = 0; i < MIPI_4LANE_CFG; i++) { - ia_css_debug_dtrace(2, "\t\t%-32s%d%-32s: %d\n", - "lane_sync_count[", i, "]", - state->lane_sync_count[i]); - } - - for (i = 0; i < MIPI_4LANE_CFG; i++) { - ia_css_debug_dtrace(2, "\t\t%-32s%d%-32s: %d\n", - "lane_rx_count[", i, "]", - state->lane_rx_count[i]); - } - - return; -} - -static void debug_print_rx_channel_state(rx_channel_state_t *state) -{ - int i; - - assert(state); - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "compression_scheme0", state->comp_scheme0); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "compression_scheme1", state->comp_scheme1); - - for (i = 0; i < N_MIPI_FORMAT_CUSTOM; i++) { - ia_css_debug_dtrace(2, "\t\t%-32s%d: %d\n", - "MIPI Predictor ", i, state->pred[i]); - } - - for (i = 0; i < N_MIPI_FORMAT_CUSTOM; i++) { - ia_css_debug_dtrace(2, "\t\t%-32s%d: %d\n", - "MIPI Compressor ", i, state->comp[i]); - } - - return; -} - -static void debug_print_rx_state(receiver_state_t *state) -{ - int i; - - assert(state); - ia_css_debug_dtrace(2, "CSI Receiver State:\n"); - - ia_css_debug_dtrace(2, "\tConfiguration:\n"); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "fs_to_ls_delay", state->fs_to_ls_delay); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "ls_to_data_delay", state->ls_to_data_delay); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "data_to_le_delay", state->data_to_le_delay); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "le_to_fe_delay", state->le_to_fe_delay); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "fe_to_fs_delay", state->fe_to_fs_delay); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "le_to_fs_delay", state->le_to_fs_delay); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "is_two_ppc", state->is_two_ppc); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "backend_rst", state->backend_rst); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "raw18", state->raw18); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "force_raw8", state->force_raw8); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "raw16", state->raw16); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "be_gsp_acc_ovl", state->be_gsp_acc_ovl); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "be_srst", state->be_srst); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "be_is_two_ppc", state->be_is_two_ppc); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "be_comp_format0", state->be_comp_format0); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "be_comp_format1", state->be_comp_format1); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "be_comp_format2", state->be_comp_format2); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "be_comp_format3", state->be_comp_format3); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "be_sel", state->be_sel); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "be_raw16_config", state->be_raw16_config); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "be_raw18_config", state->be_raw18_config); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "be_force_raw8", state->be_force_raw8); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "be_irq_status", state->be_irq_status); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "be_irq_clear", state->be_irq_clear); - - /* mipi port state */ - for (i = 0; i < N_MIPI_PORT_ID; i++) { - ia_css_debug_dtrace(2, "\tMIPI Port %d State:\n", i); - - debug_print_rx_mipi_port_state(&state->mipi_port_state[i]); - } - /* end of mipi port state */ - - /* rx channel state */ - for (i = 0; i < N_RX_CHANNEL_ID; i++) { - ia_css_debug_dtrace(2, "\tRX Channel %d State:\n", i); - - debug_print_rx_channel_state(&state->rx_channel_state[i]); - } - /* end of rx channel state */ - - return; -} -#endif - -void ia_css_debug_dump_rx_state(void) -{ -#if !defined(ISP2401) - receiver_state_t state; - - receiver_get_state(RX0_ID, &state); - debug_print_rx_state(&state); -#endif -} - void ia_css_debug_dump_sp_sw_debug_info(void) { #if SP_DEBUG != SP_DEBUG_NONE @@ -1799,57 +834,6 @@ void ia_css_debug_dump_sp_sw_debug_info(void) return; } -void ia_css_debug_dump_debug_info(const char *context) -{ - if (!context) - context = "No Context provided"; - - ia_css_debug_dtrace(2, "CSS Debug Info dump [Context = %s]\n", context); - if (!IS_ISP2401) - ia_css_debug_dump_rx_state(); - -#ifndef ISP2401 - ia_css_debug_dump_if_state(); -#endif - ia_css_debug_dump_isp_state(); - ia_css_debug_dump_isp_sp_fifo_state(); - ia_css_debug_dump_isp_gdc_fifo_state(); - ia_css_debug_dump_sp_state(); - ia_css_debug_dump_perf_counters(); - ia_css_debug_dump_dma_isp_fifo_state(); - ia_css_debug_dump_dma_sp_fifo_state(); - ia_css_debug_dump_dma_state(); - - if (!IS_ISP2401) { - struct irq_controller_state state; - - irq_controller_get_state(IRQ2_ID, &state); - - ia_css_debug_dtrace(2, "\t%-32s:\n", - "Input System IRQ Controller State"); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "irq_edge", state.irq_edge); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "irq_mask", state.irq_mask); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "irq_status", state.irq_status); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "irq_enable", state.irq_enable); - - ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", - "irq_level_not_pulse", - state.irq_level_not_pulse); - } - - ia_css_debug_tagger_state(); - - return; -} - /* this function is for debug use, it can make SP go to sleep state after each frame, then user can dump the stable SP dmem. this function can be called after ia_css_start_sp() @@ -2038,36 +1022,6 @@ void ia_css_debug_dump_isp_binary(void) } } -void ia_css_debug_dump_perf_counters(void) -{ - const struct ia_css_fw_info *fw; - int i; - unsigned int HIVE_ADDR_ia_css_isys_sp_error_cnt; - /* N_MIPI_PORT_ID + 1: 3 Capture Units and 1 Acquire Unit. */ - s32 ia_css_sp_input_system_error_cnt[N_MIPI_PORT_ID + 1]; - - if (IS_ISP2401) - return; - - ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "Input System Error Counters:\n"); - - fw = &sh_css_sp_fw; - HIVE_ADDR_ia_css_isys_sp_error_cnt = - fw->info.sp.perf_counter_input_system_error; - - (void)HIVE_ADDR_ia_css_isys_sp_error_cnt; - - sp_dmem_load(SP0_ID, - (unsigned int)sp_address_of(ia_css_isys_sp_error_cnt), - &ia_css_sp_input_system_error_cnt, - sizeof(ia_css_sp_input_system_error_cnt)); - - for (i = 0; i < N_MIPI_PORT_ID + 1; i++) { - ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "\tport[%d] = %d\n", - i, ia_css_sp_input_system_error_cnt[i]); - } -} - /* * @brief Initialize the debug mode. * Refer to "ia_css_debug.h" for more details. @@ -2939,32 +1893,6 @@ void ia_css_debug_dump_trace(void) #endif } -/* Tagger state dump function. The tagger is only available when the CSS - * contains an input system (2400 or 2401). */ -void ia_css_debug_tagger_state(void) -{ - unsigned int i; - unsigned int HIVE_ADDR_tagger_frames; - ia_css_tagger_buf_sp_elem_t tbuf_frames[MAX_CB_ELEMS_FOR_TAGGER]; - - HIVE_ADDR_tagger_frames = sh_css_sp_fw.info.sp.tagger_frames_addr; - - /* This variable is not used in crun */ - (void)HIVE_ADDR_tagger_frames; - - /* 2400 and 2401 only have 1 SP, so the tagger lives on SP0 */ - sp_dmem_load(SP0_ID, - (unsigned int)sp_address_of(tagger_frames), - tbuf_frames, - sizeof(tbuf_frames)); - - ia_css_debug_dtrace(2, "Tagger Info:\n"); - for (i = 0; i < MAX_CB_ELEMS_FOR_TAGGER; i++) { - ia_css_debug_dtrace(2, "\t tagger frame[%d]: exp_id=%d, marked=%d, locked=%d\n", - i, tbuf_frames[i].exp_id, tbuf_frames[i].mark, tbuf_frames[i].lock); - } -} - /* ISP2401 */ void ia_css_debug_pc_dump(sp_ID_t id, unsigned int num_of_dumps) { -- GitLab From 61d6b3503cda0c77da270b2c1080b1be5f1e249c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 12 Aug 2023 15:35:23 +0200 Subject: [PATCH 0361/1451] media: atomisp: Drop VIDEO_ATOMISP_ISP2401 Kconfig option Drop the VIDEO_ATOMISP_ISP2401 Kconfig option and the -DISP2401 cflags. This is no longer necessary since all ISP2400 vs ISP2401 differences are now dealt with at runtime. Many thanks to Kate Hsuan for all her work on this. Link: https://lore.kernel.org/r/20230812133523.355581-2-hdegoede@redhat.com Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/Kconfig | 12 ------------ drivers/staging/media/atomisp/Makefile | 4 ---- drivers/staging/media/atomisp/TODO | 3 --- 3 files changed, 19 deletions(-) diff --git a/drivers/staging/media/atomisp/Kconfig b/drivers/staging/media/atomisp/Kconfig index 5d8917160d41b..8197b345a5a18 100644 --- a/drivers/staging/media/atomisp/Kconfig +++ b/drivers/staging/media/atomisp/Kconfig @@ -26,18 +26,6 @@ config VIDEO_ATOMISP To compile this driver as a module, choose M here: the module will be called atomisp -config VIDEO_ATOMISP_ISP2401 - bool "Use Intel Atom ISP on Cherrytail/Anniedale (ISP2401)" - depends on VIDEO_ATOMISP - help - Enable support for Atom ISP2401-based boards. - - Select this option for Anniedale (Merrifield+ / Moorefield) - and Cherrytrail SoCs. - - Disabling it enables support for Atom ISP2400-based boards - (Merrifield and Baytrail SoCs). - if VIDEO_ATOMISP source "drivers/staging/media/atomisp/i2c/Kconfig" endif diff --git a/drivers/staging/media/atomisp/Makefile b/drivers/staging/media/atomisp/Makefile index dcf469bf1cb42..fcd3e51ae9ce9 100644 --- a/drivers/staging/media/atomisp/Makefile +++ b/drivers/staging/media/atomisp/Makefile @@ -301,8 +301,4 @@ DEFINES := -DHRT_HW -DHRT_ISP_CSS_CUSTOM_HOST -DHRT_USE_VIR_ADDRS -D__HOST__ #DEFINES += -DPUNIT_CAMERA_BUSY #DEFINES += -DUSE_KMEM_CACHE -ifeq ($(CONFIG_VIDEO_ATOMISP_ISP2401),y) -DEFINES += -DISP2401 -endif - ccflags-y += $(INCLUDES) $(DEFINES) -fno-common diff --git a/drivers/staging/media/atomisp/TODO b/drivers/staging/media/atomisp/TODO index ecf8ba67b7afa..d99cc898cd991 100644 --- a/drivers/staging/media/atomisp/TODO +++ b/drivers/staging/media/atomisp/TODO @@ -60,9 +60,6 @@ TODO 2. Items which SHOULD also be fixed eventually: -* Remove VIDEO_ATOMISP_ISP2401, making the driver to auto-detect the - register address differences between ISP2400 and ISP2401 - * The driver is intended to drive the PCI exposed versions of the device. It will not detect those devices enumerated via ACPI as a field of the i915 GPU driver (only a problem on BYT). -- GitLab From 2b5a90f08c09245de2f3422d3d1615ce6c0d8d27 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 12 Aug 2023 15:36:28 +0200 Subject: [PATCH 0362/1451] media: atomisp: gc0310: Stop setting v4l2_subdev.fwnode to the endpoint fwnode Endpoint matching is now handled by the v4l2-core and drivers no longer should set v4l2_subdev.fwnode to the endpoint fwnode. Link: https://lore.kernel.org/r/20230812133628.355812-1-hdegoede@redhat.com Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/i2c/atomisp-gc0310.c | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c index 9a11793f34f74..c438accb0472b 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c @@ -83,7 +83,6 @@ struct gc0310_device { struct mutex input_lock; bool is_streaming; - struct fwnode_handle *ep_fwnode; struct gpio_desc *reset; struct gpio_desc *powerdown; @@ -599,37 +598,37 @@ static void gc0310_remove(struct i2c_client *client) media_entity_cleanup(&dev->sd.entity); v4l2_ctrl_handler_free(&dev->ctrls.handler); mutex_destroy(&dev->input_lock); - fwnode_handle_put(dev->ep_fwnode); pm_runtime_disable(&client->dev); } static int gc0310_probe(struct i2c_client *client) { + struct fwnode_handle *ep_fwnode; struct gc0310_device *dev; int ret; - dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - /* * Sometimes the fwnode graph is initialized by the bridge driver. * Bridge drivers doing this may also add GPIO mappings, wait for this. */ - dev->ep_fwnode = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); - if (!dev->ep_fwnode) + ep_fwnode = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); + if (!ep_fwnode) return dev_err_probe(&client->dev, -EPROBE_DEFER, "waiting for fwnode graph endpoint\n"); + fwnode_handle_put(ep_fwnode); + + dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + dev->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(dev->reset)) { - fwnode_handle_put(dev->ep_fwnode); return dev_err_probe(&client->dev, PTR_ERR(dev->reset), "getting reset GPIO\n"); } dev->powerdown = devm_gpiod_get(&client->dev, "powerdown", GPIOD_OUT_HIGH); if (IS_ERR(dev->powerdown)) { - fwnode_handle_put(dev->ep_fwnode); return dev_err_probe(&client->dev, PTR_ERR(dev->powerdown), "getting powerdown GPIO\n"); } @@ -652,7 +651,6 @@ static int gc0310_probe(struct i2c_client *client) dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; dev->pad.flags = MEDIA_PAD_FL_SOURCE; dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - dev->sd.fwnode = dev->ep_fwnode; ret = gc0310_init_controls(dev); if (ret) { -- GitLab From 18fa57148abeed2fc128264f2efbf3b4fd35d50c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 13 Aug 2023 17:26:44 +0200 Subject: [PATCH 0363/1451] media: atomisp: Disable VCM for OV5693 for now ov5693 sensor modules have a VCM, but for unknown reasons the sensor fails to start streaming when instantiating a VCM i2c-client (and the runtime-pm link between VCM and sensor). Disable the VCM for now, until this is resolved. Link: https://lore.kernel.org/r/20230813152645.45834-1-hdegoede@redhat.com Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_csi2_bridge.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2_bridge.c b/drivers/staging/media/atomisp/pci/atomisp_csi2_bridge.c index 03940c11505fc..2483eaeeac733 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_csi2_bridge.c +++ b/drivers/staging/media/atomisp/pci/atomisp_csi2_bridge.c @@ -521,7 +521,12 @@ static char *atomisp_csi2_get_vcm_type(struct acpi_device *adev) } static const struct acpi_device_id atomisp_sensor_configs[] = { - ATOMISP_SENSOR_CONFIG("INT33BE", 2, true), /* OV5693 */ + /* + * FIXME ov5693 modules have a VCM, but for unknown reasons + * the sensor fails to start streaming when instantiating + * an i2c-client for the VCM, so it is disabled for now. + */ + ATOMISP_SENSOR_CONFIG("INT33BE", 2, false), /* OV5693 */ {} }; -- GitLab From a0bcd433b9bf8e256f7c0c4d8b91551dbd439fef Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 13 Aug 2023 17:26:45 +0200 Subject: [PATCH 0364/1451] media: atomisp: Drop atomisp-ov5693 sensor driver After recent improvements to atomisp driver, the atomisp driver now works fine with the standard ov5693 driver. Drop the no longer necessary atomisp specific atomisp-ov5693 sensor driver. Link: https://lore.kernel.org/r/20230813152645.45834-2-hdegoede@redhat.com Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/Kconfig | 12 - drivers/staging/media/atomisp/i2c/Makefile | 1 - .../staging/media/atomisp/i2c/ov5693/Makefile | 2 - .../staging/media/atomisp/i2c/ov5693/ad5823.h | 63 - .../media/atomisp/i2c/ov5693/atomisp-ov5693.c | 1763 ----------------- .../staging/media/atomisp/i2c/ov5693/ov5693.h | 1331 ------------- 6 files changed, 3172 deletions(-) delete mode 100644 drivers/staging/media/atomisp/i2c/ov5693/Makefile delete mode 100644 drivers/staging/media/atomisp/i2c/ov5693/ad5823.h delete mode 100644 drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c delete mode 100644 drivers/staging/media/atomisp/i2c/ov5693/ov5693.h diff --git a/drivers/staging/media/atomisp/i2c/Kconfig b/drivers/staging/media/atomisp/i2c/Kconfig index 2d4165cda2f1f..f62d183b787f5 100644 --- a/drivers/staging/media/atomisp/i2c/Kconfig +++ b/drivers/staging/media/atomisp/i2c/Kconfig @@ -57,18 +57,6 @@ config VIDEO_ATOMISP_GC0310 This is a Video4Linux2 sensor-level driver for the Galaxycore GC0310 0.3MP sensor. -config VIDEO_ATOMISP_OV5693 - tristate "Omnivision ov5693 sensor support" - depends on ACPI - depends on I2C && VIDEO_DEV - help - This is a Video4Linux2 sensor-level driver for the Micron - ov5693 5 Mpixel camera. - - ov5693 is video camera sensor. - - It currently only works with the atomisp driver. - # # Kconfig for flash drivers # diff --git a/drivers/staging/media/atomisp/i2c/Makefile b/drivers/staging/media/atomisp/i2c/Makefile index fc55af5f34226..e946cc91e5ff2 100644 --- a/drivers/staging/media/atomisp/i2c/Makefile +++ b/drivers/staging/media/atomisp/i2c/Makefile @@ -3,7 +3,6 @@ # Makefile for sensor drivers # -obj-$(CONFIG_VIDEO_ATOMISP_OV5693) += ov5693/ obj-$(CONFIG_VIDEO_ATOMISP_MT9M114) += atomisp-mt9m114.o obj-$(CONFIG_VIDEO_ATOMISP_GC2235) += atomisp-gc2235.o obj-$(CONFIG_VIDEO_ATOMISP_OV2722) += atomisp-ov2722.o diff --git a/drivers/staging/media/atomisp/i2c/ov5693/Makefile b/drivers/staging/media/atomisp/i2c/ov5693/Makefile deleted file mode 100644 index 3275f2be229e7..0000000000000 --- a/drivers/staging/media/atomisp/i2c/ov5693/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_VIDEO_ATOMISP_OV5693) += atomisp-ov5693.o diff --git a/drivers/staging/media/atomisp/i2c/ov5693/ad5823.h b/drivers/staging/media/atomisp/i2c/ov5693/ad5823.h deleted file mode 100644 index f1362cd69f6e6..0000000000000 --- a/drivers/staging/media/atomisp/i2c/ov5693/ad5823.h +++ /dev/null @@ -1,63 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Support for AD5823 VCM. - * - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - */ - -#ifndef __AD5823_H__ -#define __AD5823_H__ - -#include - -#define AD5823_VCM_ADDR 0x0c - -#define AD5823_REG_RESET 0x01 -#define AD5823_REG_MODE 0x02 -#define AD5823_REG_VCM_MOVE_TIME 0x03 -#define AD5823_REG_VCM_CODE_MSB 0x04 -#define AD5823_REG_VCM_CODE_LSB 0x05 -#define AD5823_REG_VCM_THRESHOLD_MSB 0x06 -#define AD5823_REG_VCM_THRESHOLD_LSB 0x07 - -#define AD5823_REG_LENGTH 0x1 - -#define AD5823_RING_CTRL_ENABLE 0x04 -#define AD5823_RING_CTRL_DISABLE 0x00 - -#define AD5823_RESONANCE_PERIOD 100000 -#define AD5823_RESONANCE_COEF 512 -#define AD5823_HIGH_FREQ_RANGE 0x80 - -#define VCM_CODE_MSB_MASK 0xfc -#define AD5823_INIT_FOCUS_POS 350 - -enum ad5823_tok_type { - AD5823_8BIT = 0x1, - AD5823_16BIT = 0x2, -}; - -enum ad5823_vcm_mode { - AD5823_ARC_RES0 = 0x0, /* Actuator response control RES1 */ - AD5823_ARC_RES1 = 0x1, /* Actuator response control RES0.5 */ - AD5823_ARC_RES2 = 0x2, /* Actuator response control RES2 */ - AD5823_ESRC = 0x3, /* Enhanced slew rate control */ - AD5823_DIRECT = 0x4, /* Direct control */ -}; - -#define AD5823_INVALID_CONFIG 0xffffffff -#define AD5823_MAX_FOCUS_POS 1023 -#define DELAY_PER_STEP_NS 1000000 -#define DELAY_MAX_PER_STEP_NS (1000000 * 1023) -#endif diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c deleted file mode 100644 index 460a4e34c55bd..0000000000000 --- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c +++ /dev/null @@ -1,1763 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Support for OmniVision OV5693 1080p HD camera sensor. - * - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../../include/linux/atomisp_gmin_platform.h" - -#include "ov5693.h" -#include "ad5823.h" - -#define __cci_delay(t) \ - do { \ - if ((t) < 10) { \ - usleep_range((t) * 1000, ((t) + 1) * 1000); \ - } else { \ - msleep((t)); \ - } \ - } while (0) - -/* Value 30ms reached through experimentation on byt ecs. - * The DS specifies a much lower value but when using a smaller value - * the I2C bus sometimes locks up permanently when starting the camera. - * This issue could not be reproduced on cht, so we can reduce the - * delay value to a lower value when insmod. - */ -static uint up_delay = 30; -module_param(up_delay, uint, 0644); -MODULE_PARM_DESC(up_delay, - "Delay prior to the first CCI transaction for ov5693"); - -static int vcm_ad_i2c_wr8(struct i2c_client *client, u8 reg, u8 val) -{ - int err; - struct i2c_msg msg; - u8 buf[2]; - - buf[0] = reg; - buf[1] = val; - - msg.addr = VCM_ADDR; - msg.flags = 0; - msg.len = 2; - msg.buf = &buf[0]; - - err = i2c_transfer(client->adapter, &msg, 1); - if (err != 1) { - dev_err(&client->dev, "%s: vcm i2c fail, err code = %d\n", - __func__, err); - return -EIO; - } - return 0; -} - -static int ad5823_i2c_write(struct i2c_client *client, u8 reg, u8 val) -{ - struct i2c_msg msg; - u8 buf[2]; - - buf[0] = reg; - buf[1] = val; - msg.addr = AD5823_VCM_ADDR; - msg.flags = 0; - msg.len = 0x02; - msg.buf = &buf[0]; - - if (i2c_transfer(client->adapter, &msg, 1) != 1) - return -EIO; - return 0; -} - -static int ad5823_i2c_read(struct i2c_client *client, u8 reg, u8 *val) -{ - struct i2c_msg msg[2]; - u8 buf[2]; - - buf[0] = reg; - buf[1] = 0; - - msg[0].addr = AD5823_VCM_ADDR; - msg[0].flags = 0; - msg[0].len = 0x01; - msg[0].buf = &buf[0]; - - msg[1].addr = 0x0c; - msg[1].flags = I2C_M_RD; - msg[1].len = 0x01; - msg[1].buf = &buf[1]; - *val = 0; - if (i2c_transfer(client->adapter, msg, 2) != 2) - return -EIO; - *val = buf[1]; - return 0; -} - -static const u32 ov5693_embedded_effective_size = 28; - -/* i2c read/write stuff */ -static int ov5693_read_reg(struct i2c_client *client, - u16 data_length, u16 reg, u16 *val) -{ - int err; - struct i2c_msg msg[2]; - unsigned char data[6]; - - if (!client->adapter) { - dev_err(&client->dev, "%s error, no client->adapter\n", - __func__); - return -ENODEV; - } - - if (data_length != OV5693_8BIT && data_length != OV5693_16BIT - && data_length != OV5693_32BIT) { - dev_err(&client->dev, "%s error, invalid data length\n", - __func__); - return -EINVAL; - } - - memset(msg, 0, sizeof(msg)); - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = I2C_MSG_LENGTH; - msg[0].buf = data; - - /* high byte goes out first */ - data[0] = (u8)(reg >> 8); - data[1] = (u8)(reg & 0xff); - - msg[1].addr = client->addr; - msg[1].len = data_length; - msg[1].flags = I2C_M_RD; - msg[1].buf = data; - - err = i2c_transfer(client->adapter, msg, 2); - if (err != 2) { - if (err >= 0) - err = -EIO; - dev_err(&client->dev, - "read from offset 0x%x error %d", reg, err); - return err; - } - - *val = 0; - /* high byte comes first */ - if (data_length == OV5693_8BIT) - *val = (u8)data[0]; - else if (data_length == OV5693_16BIT) - *val = be16_to_cpu(*(__be16 *)&data[0]); - else - *val = be32_to_cpu(*(__be32 *)&data[0]); - - return 0; -} - -static int ov5693_i2c_write(struct i2c_client *client, u16 len, u8 *data) -{ - struct i2c_msg msg; - const int num_msg = 1; - int ret; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = len; - msg.buf = data; - ret = i2c_transfer(client->adapter, &msg, 1); - - return ret == num_msg ? 0 : -EIO; -} - -static int vcm_dw_i2c_write(struct i2c_client *client, u16 data) -{ - struct i2c_msg msg; - const int num_msg = 1; - int ret; - __be16 val; - - val = cpu_to_be16(data); - msg.addr = VCM_ADDR; - msg.flags = 0; - msg.len = OV5693_16BIT; - msg.buf = (void *)&val; - - ret = i2c_transfer(client->adapter, &msg, 1); - - return ret == num_msg ? 0 : -EIO; -} - -/* - * Theory: per datasheet, the two VCMs both allow for a 2-byte read. - * The DW9714 doesn't actually specify what this does (it has a - * two-byte write-only protocol, but specifies the read sequence as - * legal), but it returns the same data (zeroes) always, after an - * undocumented initial NAK. The AD5823 has a one-byte address - * register to which all writes go, and subsequent reads will cycle - * through the 8 bytes of registers. Notably, the default values (the - * device is always power-cycled affirmatively, so we can rely on - * these) in AD5823 are not pairwise repetitions of the same 16 bit - * word. So all we have to do is sequentially read two bytes at a - * time and see if we detect a difference in any of the first four - * pairs. - */ -static int vcm_detect(struct i2c_client *client) -{ - int i, ret; - struct i2c_msg msg; - u16 data0 = 0, data; - - for (i = 0; i < 4; i++) { - msg.addr = VCM_ADDR; - msg.flags = I2C_M_RD; - msg.len = sizeof(data); - msg.buf = (u8 *)&data; - ret = i2c_transfer(client->adapter, &msg, 1); - - /* - * DW9714 always fails the first read and returns - * zeroes for subsequent ones - */ - if (i == 0 && ret == -EREMOTEIO) { - data0 = 0; - continue; - } - - if (i == 0) - data0 = data; - - if (data != data0) - return VCM_AD5823; - } - return ret == 1 ? VCM_DW9714 : ret; -} - -static int ov5693_write_reg(struct i2c_client *client, u16 data_length, - u16 reg, u16 val) -{ - int ret; - unsigned char data[4] = {0}; - __be16 *wreg = (void *)data; - const u16 len = data_length + sizeof(u16); /* 16-bit address + data */ - - if (data_length != OV5693_8BIT && data_length != OV5693_16BIT) { - dev_err(&client->dev, - "%s error, invalid data_length\n", __func__); - return -EINVAL; - } - - /* high byte goes out first */ - *wreg = cpu_to_be16(reg); - - if (data_length == OV5693_8BIT) { - data[2] = (u8)(val); - } else { - /* OV5693_16BIT */ - __be16 *wdata = (void *)&data[2]; - - *wdata = cpu_to_be16(val); - } - - ret = ov5693_i2c_write(client, len, data); - if (ret) - dev_err(&client->dev, - "write error: wrote 0x%x to offset 0x%x error %d", - val, reg, ret); - - return ret; -} - -/* - * ov5693_write_reg_array - Initializes a list of OV5693 registers - * @client: i2c driver client structure - * @reglist: list of registers to be written - * - * This function initializes a list of registers. When consecutive addresses - * are found in a row on the list, this function creates a buffer and sends - * consecutive data in a single i2c_transfer(). - * - * __ov5693_flush_reg_array, __ov5693_buf_reg_array() and - * __ov5693_write_reg_is_consecutive() are internal functions to - * ov5693_write_reg_array_fast() and should be not used anywhere else. - * - */ - -static int __ov5693_flush_reg_array(struct i2c_client *client, - struct ov5693_write_ctrl *ctrl) -{ - u16 size; - __be16 *reg = (void *)&ctrl->buffer.addr; - - if (ctrl->index == 0) - return 0; - - size = sizeof(u16) + ctrl->index; /* 16-bit address + data */ - - *reg = cpu_to_be16(ctrl->buffer.addr); - ctrl->index = 0; - - return ov5693_i2c_write(client, size, (u8 *)reg); -} - -static int __ov5693_buf_reg_array(struct i2c_client *client, - struct ov5693_write_ctrl *ctrl, - const struct ov5693_reg *next) -{ - int size; - __be16 *data16; - - switch (next->type) { - case OV5693_8BIT: - size = 1; - ctrl->buffer.data[ctrl->index] = (u8)next->val; - break; - case OV5693_16BIT: - size = 2; - - data16 = (void *)&ctrl->buffer.data[ctrl->index]; - *data16 = cpu_to_be16((u16)next->val); - break; - default: - return -EINVAL; - } - - /* When first item is added, we need to store its starting address */ - if (ctrl->index == 0) - ctrl->buffer.addr = next->reg; - - ctrl->index += size; - - /* - * Buffer cannot guarantee free space for u32? Better flush it to avoid - * possible lack of memory for next item. - */ - if (ctrl->index + sizeof(u16) >= OV5693_MAX_WRITE_BUF_SIZE) - return __ov5693_flush_reg_array(client, ctrl); - - return 0; -} - -static int __ov5693_write_reg_is_consecutive(struct i2c_client *client, - struct ov5693_write_ctrl *ctrl, - const struct ov5693_reg *next) -{ - if (ctrl->index == 0) - return 1; - - return ctrl->buffer.addr + ctrl->index == next->reg; -} - -static int ov5693_write_reg_array(struct i2c_client *client, - const struct ov5693_reg *reglist) -{ - const struct ov5693_reg *next = reglist; - struct ov5693_write_ctrl ctrl; - int err; - - ctrl.index = 0; - for (; next->type != OV5693_TOK_TERM; next++) { - switch (next->type & OV5693_TOK_MASK) { - case OV5693_TOK_DELAY: - err = __ov5693_flush_reg_array(client, &ctrl); - if (err) - return err; - msleep(next->val); - break; - default: - /* - * If next address is not consecutive, data needs to be - * flushed before proceed. - */ - if (!__ov5693_write_reg_is_consecutive(client, &ctrl, - next)) { - err = __ov5693_flush_reg_array(client, &ctrl); - if (err) - return err; - } - err = __ov5693_buf_reg_array(client, &ctrl, next); - if (err) { - dev_err(&client->dev, - "%s: write error, aborted\n", - __func__); - return err; - } - break; - } - } - - return __ov5693_flush_reg_array(client, &ctrl); -} - -static long __ov5693_set_exposure(struct v4l2_subdev *sd, int coarse_itg, - int gain, int digitgain) - -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov5693_device *dev = to_ov5693_sensor(sd); - u16 vts, hts; - int ret, exp_val; - - hts = ov5693_res[dev->fmt_idx].pixels_per_line; - vts = ov5693_res[dev->fmt_idx].lines_per_frame; - /* - * If coarse_itg is larger than 1<<15, can not write to reg directly. - * The way is to write coarse_itg/2 to the reg, meanwhile write 2*hts - * to the reg. - */ - if (coarse_itg > (1 << 15)) { - hts = hts * 2; - coarse_itg = (int)coarse_itg / 2; - } - /* group hold */ - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_GROUP_ACCESS, 0x00); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_GROUP_ACCESS); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_TIMING_HTS_H, (hts >> 8) & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_TIMING_HTS_H); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_TIMING_HTS_L, hts & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_TIMING_HTS_L); - return ret; - } - /* Increase the VTS to match exposure + MARGIN */ - if (coarse_itg > vts - OV5693_INTEGRATION_TIME_MARGIN) - vts = (u16)coarse_itg + OV5693_INTEGRATION_TIME_MARGIN; - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_TIMING_VTS_H, (vts >> 8) & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_TIMING_VTS_H); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_TIMING_VTS_L, vts & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_TIMING_VTS_L); - return ret; - } - - /* set exposure */ - - /* Lower four bit should be 0*/ - exp_val = coarse_itg << 4; - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_L, exp_val & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_EXPOSURE_L); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_M, (exp_val >> 8) & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_EXPOSURE_M); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_H, (exp_val >> 16) & 0x0F); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_EXPOSURE_H); - return ret; - } - - /* Analog gain */ - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_AGC_L, gain & 0xff); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_AGC_L); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_AGC_H, (gain >> 8) & 0xff); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_AGC_H); - return ret; - } - - /* Digital gain */ - if (digitgain) { - ret = ov5693_write_reg(client, OV5693_16BIT, - OV5693_MWB_RED_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_MWB_RED_GAIN_H); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_16BIT, - OV5693_MWB_GREEN_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_MWB_RED_GAIN_H); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_16BIT, - OV5693_MWB_BLUE_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_MWB_RED_GAIN_H); - return ret; - } - } - - /* End group */ - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_GROUP_ACCESS, 0x10); - if (ret) - return ret; - - /* Delay launch group */ - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_GROUP_ACCESS, 0xa0); - if (ret) - return ret; - return ret; -} - -static int ov5693_set_exposure(struct v4l2_subdev *sd, int exposure, - int gain, int digitgain) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - int ret; - - mutex_lock(&dev->input_lock); - ret = __ov5693_set_exposure(sd, exposure, gain, digitgain); - mutex_unlock(&dev->input_lock); - - return ret; -} - -static long ov5693_s_exposure(struct v4l2_subdev *sd, - struct atomisp_exposure *exposure) -{ - u16 coarse_itg = exposure->integration_time[0]; - u16 analog_gain = exposure->gain[0]; - u16 digital_gain = exposure->gain[1]; - - /* we should not accept the invalid value below */ - if (analog_gain == 0) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - - v4l2_err(client, "%s: invalid value\n", __func__); - return -EINVAL; - } - return ov5693_set_exposure(sd, coarse_itg, analog_gain, digital_gain); -} - -static int ov5693_read_otp_reg_array(struct i2c_client *client, u16 size, - u16 addr, u8 *buf) -{ - u16 index; - int ret; - u16 *pVal = NULL; - - for (index = 0; index <= size; index++) { - pVal = (u16 *)(buf + index); - ret = - ov5693_read_reg(client, OV5693_8BIT, addr + index, - pVal); - if (ret) - return ret; - } - - return 0; -} - -static int __ov5693_otp_read(struct v4l2_subdev *sd, u8 *buf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov5693_device *dev = to_ov5693_sensor(sd); - int ret; - int i; - u8 *b = buf; - - dev->otp_size = 0; - for (i = 1; i < OV5693_OTP_BANK_MAX; i++) { - /*set bank NO and OTP read mode. */ - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_BANK_REG, - (i | 0xc0)); //[7:6] 2'b11 [5:0] bank no - if (ret) { - dev_err(&client->dev, "failed to prepare OTP page\n"); - return ret; - } - //pr_debug("write 0x%x->0x%x\n",OV5693_OTP_BANK_REG,(i|0xc0)); - - /*enable read */ - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_READ_REG, - OV5693_OTP_MODE_READ); // enable :1 - if (ret) { - dev_err(&client->dev, - "failed to set OTP reading mode page"); - return ret; - } - //pr_debug("write 0x%x->0x%x\n",OV5693_OTP_READ_REG,OV5693_OTP_MODE_READ); - - /* Reading the OTP data array */ - ret = ov5693_read_otp_reg_array(client, OV5693_OTP_BANK_SIZE, - OV5693_OTP_START_ADDR, - b); - if (ret) { - dev_err(&client->dev, "failed to read OTP data\n"); - return ret; - } - - //pr_debug("BANK[%2d] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", i, *b, *(b+1), *(b+2), *(b+3), *(b+4), *(b+5), *(b+6), *(b+7), *(b+8), *(b+9), *(b+10), *(b+11), *(b+12), *(b+13), *(b+14), *(b+15)); - - //Intel OTP map, try to read 320byts first. - if (i == 21) { - if ((*b) == 0) { - dev->otp_size = 320; - break; - } else { - b = buf; - continue; - } - } else if (i == - 24) { //if the first 320bytes data doesn't not exist, try to read the next 32bytes data. - if ((*b) == 0) { - dev->otp_size = 32; - break; - } else { - b = buf; - continue; - } - } else if (i == - 27) { //if the prvious 32bytes data doesn't exist, try to read the next 32bytes data again. - if ((*b) == 0) { - dev->otp_size = 32; - break; - } else { - dev->otp_size = 0; // no OTP data. - break; - } - } - - b = b + OV5693_OTP_BANK_SIZE; - } - return 0; -} - -/* - * Read otp data and store it into a kmalloced buffer. - * The caller must kfree the buffer when no more needed. - * @size: set to the size of the returned otp data. - */ -static void *ov5693_otp_read(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 *buf; - int ret; - - buf = devm_kzalloc(&client->dev, (OV5693_OTP_DATA_SIZE + 16), GFP_KERNEL); - if (!buf) - return ERR_PTR(-ENOMEM); - - //otp valid after mipi on and sw stream on - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_FRAME_OFF_NUM, 0x00); - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_SW_STREAM, OV5693_START_STREAMING); - - ret = __ov5693_otp_read(sd, buf); - - //mipi off and sw stream off after otp read - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_FRAME_OFF_NUM, 0x0f); - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_SW_STREAM, OV5693_STOP_STREAMING); - - /* Driver has failed to find valid data */ - if (ret) { - dev_err(&client->dev, "sensor found no valid OTP data\n"); - return ERR_PTR(ret); - } - - return buf; -} - -static long ov5693_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - switch (cmd) { - case ATOMISP_IOC_S_EXPOSURE: - return ov5693_s_exposure(sd, arg); - default: - return -EINVAL; - } - return 0; -} - -/* - * This returns the exposure time being used. This should only be used - * for filling in EXIF data, not for actual image processing. - */ -static int ov5693_q_exposure(struct v4l2_subdev *sd, s32 *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 reg_v, reg_v2; - int ret; - - /* get exposure */ - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_L, - ®_v); - if (ret) - goto err; - - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_M, - ®_v2); - if (ret) - goto err; - - reg_v += reg_v2 << 8; - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_H, - ®_v2); - if (ret) - goto err; - - *value = reg_v + (((u32)reg_v2 << 16)); -err: - return ret; -} - -static int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u8 vcm_code; - - ret = ad5823_i2c_read(client, AD5823_REG_VCM_CODE_MSB, &vcm_code); - if (ret) - return ret; - - /* set reg VCM_CODE_MSB Bit[1:0] */ - vcm_code = (vcm_code & VCM_CODE_MSB_MASK) | - ((val >> 8) & ~VCM_CODE_MSB_MASK); - ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB, vcm_code); - if (ret) - return ret; - - /* set reg VCM_CODE_LSB Bit[7:0] */ - ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_LSB, (val & 0xff)); - if (ret) - return ret; - - /* set required vcm move time */ - vcm_code = AD5823_RESONANCE_PERIOD / AD5823_RESONANCE_COEF - - AD5823_HIGH_FREQ_RANGE; - ret = ad5823_i2c_write(client, AD5823_REG_VCM_MOVE_TIME, vcm_code); - - return ret; -} - -static int ad5823_t_focus_abs(struct v4l2_subdev *sd, s32 value) -{ - value = min(value, AD5823_MAX_FOCUS_POS); - return ad5823_t_focus_vcm(sd, value); -} - -static int ov5693_t_focus_abs(struct v4l2_subdev *sd, s32 value) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - dev_dbg(&client->dev, "%s: FOCUS_POS: 0x%x\n", __func__, value); - value = clamp(value, 0, OV5693_VCM_MAX_FOCUS_POS); - if (dev->vcm == VCM_DW9714) { - if (dev->vcm_update) { - ret = vcm_dw_i2c_write(client, VCM_PROTECTION_OFF); - if (ret) - return ret; - ret = vcm_dw_i2c_write(client, DIRECT_VCM); - if (ret) - return ret; - ret = vcm_dw_i2c_write(client, VCM_PROTECTION_ON); - if (ret) - return ret; - dev->vcm_update = false; - } - ret = vcm_dw_i2c_write(client, - vcm_val(value, VCM_DEFAULT_S)); - } else if (dev->vcm == VCM_AD5823) { - ad5823_t_focus_abs(sd, value); - } - if (ret == 0) { - dev->number_of_steps = value - dev->focus; - dev->focus = value; - dev->timestamp_t_focus_abs = ktime_get(); - } else - dev_err(&client->dev, - "%s: i2c failed. ret %d\n", __func__, ret); - - return ret; -} - -static int ov5693_t_focus_rel(struct v4l2_subdev *sd, s32 value) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - - return ov5693_t_focus_abs(sd, dev->focus + value); -} - -#define DELAY_PER_STEP_NS 1000000 -#define DELAY_MAX_PER_STEP_NS (1000000 * 1023) -static int ov5693_q_focus_status(struct v4l2_subdev *sd, s32 *value) -{ - u32 status = 0; - struct ov5693_device *dev = to_ov5693_sensor(sd); - ktime_t temptime; - ktime_t timedelay = ns_to_ktime(min_t(u32, - abs(dev->number_of_steps) * DELAY_PER_STEP_NS, - DELAY_MAX_PER_STEP_NS)); - - temptime = ktime_sub(ktime_get(), (dev->timestamp_t_focus_abs)); - if (ktime_compare(temptime, timedelay) <= 0) { - status |= ATOMISP_FOCUS_STATUS_MOVING; - status |= ATOMISP_FOCUS_HP_IN_PROGRESS; - } else { - status |= ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE; - status |= ATOMISP_FOCUS_HP_COMPLETE; - } - - *value = status; - - return 0; -} - -static int ov5693_q_focus_abs(struct v4l2_subdev *sd, s32 *value) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - s32 val; - - ov5693_q_focus_status(sd, &val); - - if (val & ATOMISP_FOCUS_STATUS_MOVING) - *value = dev->focus - dev->number_of_steps; - else - *value = dev->focus; - - return 0; -} - -static int ov5693_t_vcm_slew(struct v4l2_subdev *sd, s32 value) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - - dev->number_of_steps = value; - dev->vcm_update = true; - return 0; -} - -static int ov5693_t_vcm_timing(struct v4l2_subdev *sd, s32 value) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - - dev->number_of_steps = value; - dev->vcm_update = true; - return 0; -} - -static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov5693_device *dev = - container_of(ctrl->handler, struct ov5693_device, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_FOCUS_ABSOLUTE: - dev_dbg(&client->dev, "%s: CID_FOCUS_ABSOLUTE:%d.\n", - __func__, ctrl->val); - ret = ov5693_t_focus_abs(&dev->sd, ctrl->val); - break; - case V4L2_CID_FOCUS_RELATIVE: - dev_dbg(&client->dev, "%s: CID_FOCUS_RELATIVE:%d.\n", - __func__, ctrl->val); - ret = ov5693_t_focus_rel(&dev->sd, ctrl->val); - break; - case V4L2_CID_VCM_SLEW: - ret = ov5693_t_vcm_slew(&dev->sd, ctrl->val); - break; - case V4L2_CID_VCM_TIMING: - ret = ov5693_t_vcm_timing(&dev->sd, ctrl->val); - break; - default: - ret = -EINVAL; - } - return ret; -} - -static int ov5693_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov5693_device *dev = - container_of(ctrl->handler, struct ov5693_device, ctrl_handler); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE_ABSOLUTE: - ret = ov5693_q_exposure(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCUS_ABSOLUTE: - ret = ov5693_q_focus_abs(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCUS_STATUS: - ret = ov5693_q_focus_status(&dev->sd, &ctrl->val); - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .s_ctrl = ov5693_s_ctrl, - .g_volatile_ctrl = ov5693_g_volatile_ctrl -}; - -static const struct v4l2_ctrl_config ov5693_controls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .min = 0x0, - .max = 0xffff, - .step = 0x01, - .def = 0x00, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCUS_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focus move absolute", - .min = 0, - .max = OV5693_VCM_MAX_FOCUS_POS, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCUS_RELATIVE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focus move relative", - .min = OV5693_VCM_MAX_FOCUS_NEG, - .max = OV5693_VCM_MAX_FOCUS_POS, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCUS_STATUS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focus status", - .min = 0, - .max = 100, /* allow enum to grow in the future */ - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_VCM_SLEW, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vcm slew", - .min = 0, - .max = OV5693_VCM_SLEW_STEP_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_VCM_TIMING, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vcm step time", - .min = 0, - .max = OV5693_VCM_SLEW_TIME_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, -}; - -static int ov5693_init(struct v4l2_subdev *sd) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - pr_info("%s\n", __func__); - mutex_lock(&dev->input_lock); - dev->vcm_update = false; - - if (dev->vcm == VCM_AD5823) { - ret = vcm_ad_i2c_wr8(client, 0x01, 0x01); /* vcm init test */ - if (ret) - dev_err(&client->dev, - "vcm reset failed\n"); - /*change the mode*/ - ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB, - AD5823_RING_CTRL_ENABLE); - if (ret) - dev_err(&client->dev, - "vcm enable ringing failed\n"); - ret = ad5823_i2c_write(client, AD5823_REG_MODE, - AD5823_ARC_RES1); - if (ret) - dev_err(&client->dev, - "vcm change mode failed\n"); - } - - /*change initial focus value for ad5823*/ - if (dev->vcm == VCM_AD5823) { - dev->focus = AD5823_INIT_FOCUS_POS; - ov5693_t_focus_abs(sd, AD5823_INIT_FOCUS_POS); - } else { - dev->focus = 0; - ov5693_t_focus_abs(sd, 0); - } - - mutex_unlock(&dev->input_lock); - - return 0; -} - -static int power_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret; - struct ov5693_device *dev = to_ov5693_sensor(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* - * This driver assumes "internal DVDD, PWDNB tied to DOVDD". - * In this set up only gpio0 (XSHUTDN) should be available - * but in some products (for example ECS) gpio1 (PWDNB) is - * also available. If gpio1 is available we emulate it being - * tied to DOVDD here. - */ - if (flag) { - ret = dev->platform_data->v2p8_ctrl(sd, 1); - dev->platform_data->gpio1_ctrl(sd, 1); - if (ret == 0) { - ret = dev->platform_data->v1p8_ctrl(sd, 1); - if (ret) { - dev->platform_data->gpio1_ctrl(sd, 0); - ret = dev->platform_data->v2p8_ctrl(sd, 0); - } - } - } else { - dev->platform_data->gpio1_ctrl(sd, 0); - ret = dev->platform_data->v1p8_ctrl(sd, 0); - ret |= dev->platform_data->v2p8_ctrl(sd, 0); - } - - return ret; -} - -static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - return dev->platform_data->gpio0_ctrl(sd, flag); -} - -static int __power_up(struct v4l2_subdev *sd) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - - /* power control */ - ret = power_ctrl(sd, 1); - if (ret) - goto fail_power; - - /* according to DS, at least 5ms is needed between DOVDD and PWDN */ - /* add this delay time to 10~11ms*/ - usleep_range(10000, 11000); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 1); - if (ret) { - ret = gpio_ctrl(sd, 1); - if (ret) - goto fail_power; - } - - /* flis clock control */ - ret = dev->platform_data->flisclk_ctrl(sd, 1); - if (ret) - goto fail_clk; - - __cci_delay(up_delay); - - return 0; - -fail_clk: - gpio_ctrl(sd, 0); -fail_power: - power_ctrl(sd, 0); - dev_err(&client->dev, "sensor power-up failed\n"); - - return ret; -} - -static int power_down(struct v4l2_subdev *sd) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - dev->focus = OV5693_INVALID_CONFIG; - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - - ret = dev->platform_data->flisclk_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "flisclk failed\n"); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 0); - if (ret) { - ret = gpio_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "gpio failed 2\n"); - } - - /* power control */ - ret = power_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "vprog failed.\n"); - - return ret; -} - -static int power_up(struct v4l2_subdev *sd) -{ - static const int retry_count = 4; - int i, ret; - - for (i = 0; i < retry_count; i++) { - ret = __power_up(sd); - if (!ret) - return 0; - - power_down(sd); - } - return ret; -} - -static int ov5693_s_power(struct v4l2_subdev *sd, int on) -{ - int ret; - - pr_info("%s: on %d\n", __func__, on); - if (on == 0) - return power_down(sd); - else { - ret = power_up(sd); - if (!ret) { - ret = ov5693_init(sd); - /* restore settings */ - ov5693_res = ov5693_res_preview; - N_RES = N_RES_PREVIEW; - } - } - return ret; -} - -/* - * distance - calculate the distance - * @res: resolution - * @w: width - * @h: height - * - * Get the gap between res_w/res_h and w/h. - * distance = (res_w/res_h - w/h) / (w/h) * 8192 - * res->width/height smaller than w/h wouldn't be considered. - * The gap of ratio larger than 1/8 wouldn't be considered. - * Returns the value of gap or -1 if fail. - */ -#define LARGEST_ALLOWED_RATIO_MISMATCH 1024 -static int distance(struct ov5693_resolution *res, u32 w, u32 h) -{ - int ratio; - int distance; - - if (w == 0 || h == 0 || - res->width < w || res->height < h) - return -1; - - ratio = res->width << 13; - ratio /= w; - ratio *= h; - ratio /= res->height; - - distance = abs(ratio - 8192); - - if (distance > LARGEST_ALLOWED_RATIO_MISMATCH) - return -1; - - return distance; -} - -/* Return the nearest higher resolution index - * Firstly try to find the approximate aspect ratio resolution - * If we find multiple same AR resolutions, choose the - * minimal size. - */ -static int nearest_resolution_index(int w, int h) -{ - int i; - int idx = -1; - int dist; - int min_dist = INT_MAX; - int min_res_w = INT_MAX; - struct ov5693_resolution *tmp_res = NULL; - - for (i = 0; i < N_RES; i++) { - tmp_res = &ov5693_res[i]; - dist = distance(tmp_res, w, h); - if (dist == -1) - continue; - if (dist < min_dist) { - min_dist = dist; - idx = i; - min_res_w = ov5693_res[i].width; - continue; - } - if (dist == min_dist && ov5693_res[i].width < min_res_w) - idx = i; - } - - return idx; -} - -static int get_resolution_index(int w, int h) -{ - int i; - - for (i = 0; i < N_RES; i++) { - if (w != ov5693_res[i].width) - continue; - if (h != ov5693_res[i].height) - continue; - - return i; - } - - return -1; -} - -/* TODO: remove it. */ -static int startup(struct v4l2_subdev *sd) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_SW_RESET, 0x01); - if (ret) { - dev_err(&client->dev, "ov5693 reset err.\n"); - return ret; - } - - ret = ov5693_write_reg_array(client, ov5693_global_setting); - if (ret) { - dev_err(&client->dev, "ov5693 write register err.\n"); - return ret; - } - - ret = ov5693_write_reg_array(client, ov5693_res[dev->fmt_idx].regs); - if (ret) { - dev_err(&client->dev, "ov5693 write register err.\n"); - return ret; - } - - return ret; -} - -static int ov5693_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_mipi_info *ov5693_info = NULL; - int ret = 0; - int idx; - - if (format->pad) - return -EINVAL; - if (!fmt) - return -EINVAL; - ov5693_info = v4l2_get_subdev_hostdata(sd); - if (!ov5693_info) - return -EINVAL; - - mutex_lock(&dev->input_lock); - idx = nearest_resolution_index(fmt->width, fmt->height); - if (idx == -1) { - /* return the largest resolution */ - fmt->width = ov5693_res[N_RES - 1].width; - fmt->height = ov5693_res[N_RES - 1].height; - } else { - fmt->width = ov5693_res[idx].width; - fmt->height = ov5693_res[idx].height; - } - - fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - sd_state->pads->try_fmt = *fmt; - mutex_unlock(&dev->input_lock); - return 0; - } - - dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); - if (dev->fmt_idx == -1) { - dev_err(&client->dev, "get resolution fail\n"); - mutex_unlock(&dev->input_lock); - return -EINVAL; - } - - ret = startup(sd); - if (ret) { - int i = 0; - - dev_err(&client->dev, "ov5693 startup err, retry to power up\n"); - for (i = 0; i < OV5693_POWER_UP_RETRY_NUM; i++) { - dev_err(&client->dev, - "ov5693 retry to power up %d/%d times, result: ", - i + 1, OV5693_POWER_UP_RETRY_NUM); - power_down(sd); - ret = power_up(sd); - if (!ret) { - mutex_unlock(&dev->input_lock); - ov5693_init(sd); - mutex_lock(&dev->input_lock); - } else { - dev_err(&client->dev, "power up failed, continue\n"); - continue; - } - ret = startup(sd); - if (ret) { - dev_err(&client->dev, " startup FAILED!\n"); - } else { - dev_err(&client->dev, " startup SUCCESS!\n"); - break; - } - } - } - - /* - * After sensor settings are set to HW, sometimes stream is started. - * This would cause ISP timeout because ISP is not ready to receive - * data yet. So add stop streaming here. - */ - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM, - OV5693_STOP_STREAMING); - if (ret) - dev_warn(&client->dev, "ov5693 stream off err\n"); - - ov5693_info->metadata_width = fmt->width * 10 / 8; - ov5693_info->metadata_height = 1; - ov5693_info->metadata_effective_width = &ov5693_embedded_effective_size; - - mutex_unlock(&dev->input_lock); - return ret; -} - -static int ov5693_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct ov5693_device *dev = to_ov5693_sensor(sd); - - if (format->pad) - return -EINVAL; - - if (!fmt) - return -EINVAL; - - fmt->width = ov5693_res[dev->fmt_idx].width; - fmt->height = ov5693_res[dev->fmt_idx].height; - fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; - - return 0; -} - -static int ov5693_detect(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - u16 high, low; - int ret; - u16 id; - u8 revision; - - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) - return -ENODEV; - - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_SC_CMMN_CHIP_ID_H, &high); - if (ret) { - dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); - return -ENODEV; - } - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_SC_CMMN_CHIP_ID_L, &low); - if (ret) - return ret; - id = ((((u16)high) << 8) | (u16)low); - - if (id != OV5693_ID) { - dev_err(&client->dev, "sensor ID error 0x%x\n", id); - return -ENODEV; - } - - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_SC_CMMN_SUB_ID, &high); - revision = (u8)high & 0x0f; - - dev_dbg(&client->dev, "sensor_revision = 0x%x\n", revision); - dev_dbg(&client->dev, "detect ov5693 success\n"); - return 0; -} - -static int ov5693_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - mutex_lock(&dev->input_lock); - - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM, - enable ? OV5693_START_STREAMING : - OV5693_STOP_STREAMING); - - mutex_unlock(&dev->input_lock); - - return ret; -} - -static int ov5693_s_config(struct v4l2_subdev *sd, - int irq, void *platform_data) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - if (!platform_data) - return -ENODEV; - - dev->platform_data = - (struct camera_sensor_platform_data *)platform_data; - - mutex_lock(&dev->input_lock); - /* power off the module, then power on it in future - * as first power on by board may not fulfill the - * power on sequqence needed by the module - */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "ov5693 power-off err.\n"); - goto fail_power_off; - } - - ret = power_up(sd); - if (ret) { - dev_err(&client->dev, "ov5693 power-up err.\n"); - goto fail_power_on; - } - - if (!dev->vcm) - dev->vcm = vcm_detect(client); - - ret = dev->platform_data->csi_cfg(sd, 1); - if (ret) - goto fail_csi_cfg; - - /* config & detect sensor */ - ret = ov5693_detect(client); - if (ret) { - dev_err(&client->dev, "ov5693_detect err s_config.\n"); - goto fail_csi_cfg; - } - - dev->otp_data = ov5693_otp_read(sd); - - /* turn off sensor, after probed */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "ov5693 power-off err.\n"); - goto fail_csi_cfg; - } - mutex_unlock(&dev->input_lock); - - return ret; - -fail_csi_cfg: - dev->platform_data->csi_cfg(sd, 0); -fail_power_on: - power_down(sd); - dev_err(&client->dev, "sensor power-gating failed\n"); -fail_power_off: - mutex_unlock(&dev->input_lock); - return ret; -} - -static int ov5693_g_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - - interval->interval.numerator = 1; - interval->interval.denominator = ov5693_res[dev->fmt_idx].fps; - - return 0; -} - -static int ov5693_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->index >= MAX_FMTS) - return -EINVAL; - - code->code = MEDIA_BUS_FMT_SBGGR10_1X10; - return 0; -} - -static int ov5693_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_size_enum *fse) -{ - int index = fse->index; - - if (index >= N_RES) - return -EINVAL; - - fse->min_width = ov5693_res[index].width; - fse->min_height = ov5693_res[index].height; - fse->max_width = ov5693_res[index].width; - fse->max_height = ov5693_res[index].height; - - return 0; -} - -static const struct v4l2_subdev_video_ops ov5693_video_ops = { - .s_stream = ov5693_s_stream, - .g_frame_interval = ov5693_g_frame_interval, -}; - -static const struct v4l2_subdev_core_ops ov5693_core_ops = { - .s_power = ov5693_s_power, - .ioctl = ov5693_ioctl, -}; - -static const struct v4l2_subdev_pad_ops ov5693_pad_ops = { - .enum_mbus_code = ov5693_enum_mbus_code, - .enum_frame_size = ov5693_enum_frame_size, - .get_fmt = ov5693_get_fmt, - .set_fmt = ov5693_set_fmt, -}; - -static const struct v4l2_subdev_ops ov5693_ops = { - .core = &ov5693_core_ops, - .video = &ov5693_video_ops, - .pad = &ov5693_pad_ops, -}; - -static void ov5693_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov5693_device *dev = to_ov5693_sensor(sd); - - dev_dbg(&client->dev, "ov5693_remove...\n"); - - dev->platform_data->csi_cfg(sd, 0); - - v4l2_device_unregister_subdev(sd); - - atomisp_gmin_remove_subdev(sd); - - media_entity_cleanup(&dev->sd.entity); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - kfree(dev); -} - -static int ov5693_probe(struct i2c_client *client) -{ - struct ov5693_device *dev; - int i2c; - int ret; - void *pdata; - unsigned int i; - - /* - * Firmware workaround: Some modules use a "secondary default" - * address of 0x10 which doesn't appear on schematics, and - * some BIOS versions haven't gotten the memo. Work around - * via config. - */ - i2c = gmin_get_var_int(&client->dev, false, "I2CAddr", -1); - if (i2c != -1) { - dev_info(&client->dev, - "Overriding firmware-provided I2C address (0x%x) with 0x%x\n", - client->addr, i2c); - client->addr = i2c; - } - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - mutex_init(&dev->input_lock); - - dev->fmt_idx = 0; - v4l2_i2c_subdev_init(&dev->sd, client, &ov5693_ops); - - pdata = gmin_camera_platform_data(&dev->sd, - ATOMISP_INPUT_FORMAT_RAW_10, - atomisp_bayer_order_bggr); - if (!pdata) { - ret = -EINVAL; - goto out_free; - } - - ret = ov5693_s_config(&dev->sd, client->irq, pdata); - if (ret) - goto out_free; - - ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); - if (ret) - goto out_free; - - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - ret = - v4l2_ctrl_handler_init(&dev->ctrl_handler, - ARRAY_SIZE(ov5693_controls)); - if (ret) { - ov5693_remove(client); - return ret; - } - - for (i = 0; i < ARRAY_SIZE(ov5693_controls); i++) - v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov5693_controls[i], - NULL); - - if (dev->ctrl_handler.error) { - ov5693_remove(client); - return dev->ctrl_handler.error; - } - - /* Use same lock for controls as for everything else. */ - dev->ctrl_handler.lock = &dev->input_lock; - dev->sd.ctrl_handler = &dev->ctrl_handler; - - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); - if (ret) - ov5693_remove(client); - - return ret; -out_free: - v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); - return ret; -} - -static const struct acpi_device_id ov5693_acpi_match[] = { - {"INT33BE"}, - {}, -}; -MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match); - -static struct i2c_driver ov5693_driver = { - .driver = { - .name = "ov5693", - .acpi_match_table = ov5693_acpi_match, - }, - .probe = ov5693_probe, - .remove = ov5693_remove, -}; -module_i2c_driver(ov5693_driver); - -MODULE_DESCRIPTION("A low-level driver for OmniVision 5693 sensors"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h deleted file mode 100644 index 5e17eaf8fd6e8..0000000000000 --- a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h +++ /dev/null @@ -1,1331 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Support for OmniVision OV5693 5M camera sensor. - * - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - */ - -#ifndef __OV5693_H__ -#define __OV5693_H__ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../include/linux/atomisp_platform.h" - -/* - * FIXME: non-preview resolutions are currently broken - */ -#define ENABLE_NON_PREVIEW 0 - -#define OV5693_POWER_UP_RETRY_NUM 5 - -/* Defines for register writes and register array processing */ -#define I2C_MSG_LENGTH 0x2 -#define I2C_RETRY_COUNT 5 - -#define OV5693_FOCAL_LENGTH_NUM 334 /*3.34mm*/ -#define OV5693_FOCAL_LENGTH_DEM 100 -#define OV5693_F_NUMBER_DEFAULT_NUM 24 -#define OV5693_F_NUMBER_DEM 10 - -#define MAX_FMTS 1 - -/* sensor_mode_data read_mode adaptation */ -#define OV5693_READ_MODE_BINNING_ON 0x0400 -#define OV5693_READ_MODE_BINNING_OFF 0x00 -#define OV5693_INTEGRATION_TIME_MARGIN 8 - -#define OV5693_MAX_EXPOSURE_VALUE 0xFFF1 -#define OV5693_MAX_GAIN_VALUE 0xFF - -/* - * focal length bits definition: - * bits 31-16: numerator, bits 15-0: denominator - */ -#define OV5693_FOCAL_LENGTH_DEFAULT 0x1B70064 - -/* - * current f-number bits definition: - * bits 31-16: numerator, bits 15-0: denominator - */ -#define OV5693_F_NUMBER_DEFAULT 0x18000a - -/* - * f-number range bits definition: - * bits 31-24: max f-number numerator - * bits 23-16: max f-number denominator - * bits 15-8: min f-number numerator - * bits 7-0: min f-number denominator - */ -#define OV5693_F_NUMBER_RANGE 0x180a180a -#define OV5693_ID 0x5690 - -#define OV5693_FINE_INTG_TIME_MIN 0 -#define OV5693_FINE_INTG_TIME_MAX_MARGIN 0 -#define OV5693_COARSE_INTG_TIME_MIN 1 -#define OV5693_COARSE_INTG_TIME_MAX_MARGIN 6 - -#define OV5693_BIN_FACTOR_MAX 4 -/* - * OV5693 System control registers - */ -#define OV5693_SW_SLEEP 0x0100 -#define OV5693_SW_RESET 0x0103 -#define OV5693_SW_STREAM 0x0100 - -#define OV5693_SC_CMMN_CHIP_ID_H 0x300A -#define OV5693_SC_CMMN_CHIP_ID_L 0x300B -#define OV5693_SC_CMMN_SCCB_ID 0x300C -#define OV5693_SC_CMMN_SUB_ID 0x302A /* process, version*/ -/*Bit[7:4] Group control, Bit[3:0] Group ID*/ -#define OV5693_GROUP_ACCESS 0x3208 -/* -*Bit[3:0] Bit[19:16] of exposure, -*remaining 16 bits lies in Reg0x3501&Reg0x3502 -*/ -#define OV5693_EXPOSURE_H 0x3500 -#define OV5693_EXPOSURE_M 0x3501 -#define OV5693_EXPOSURE_L 0x3502 -/*Bit[1:0] means Bit[9:8] of gain*/ -#define OV5693_AGC_H 0x350A -#define OV5693_AGC_L 0x350B /*Bit[7:0] of gain*/ - -#define OV5693_HORIZONTAL_START_H 0x3800 /*Bit[11:8]*/ -#define OV5693_HORIZONTAL_START_L 0x3801 /*Bit[7:0]*/ -#define OV5693_VERTICAL_START_H 0x3802 /*Bit[11:8]*/ -#define OV5693_VERTICAL_START_L 0x3803 /*Bit[7:0]*/ -#define OV5693_HORIZONTAL_END_H 0x3804 /*Bit[11:8]*/ -#define OV5693_HORIZONTAL_END_L 0x3805 /*Bit[7:0]*/ -#define OV5693_VERTICAL_END_H 0x3806 /*Bit[11:8]*/ -#define OV5693_VERTICAL_END_L 0x3807 /*Bit[7:0]*/ -#define OV5693_HORIZONTAL_OUTPUT_SIZE_H 0x3808 /*Bit[3:0]*/ -#define OV5693_HORIZONTAL_OUTPUT_SIZE_L 0x3809 /*Bit[7:0]*/ -#define OV5693_VERTICAL_OUTPUT_SIZE_H 0x380a /*Bit[3:0]*/ -#define OV5693_VERTICAL_OUTPUT_SIZE_L 0x380b /*Bit[7:0]*/ -/*High 8-bit, and low 8-bit HTS address is 0x380d*/ -#define OV5693_TIMING_HTS_H 0x380C -/*High 8-bit, and low 8-bit HTS address is 0x380d*/ -#define OV5693_TIMING_HTS_L 0x380D -/*High 8-bit, and low 8-bit HTS address is 0x380f*/ -#define OV5693_TIMING_VTS_H 0x380e -/*High 8-bit, and low 8-bit HTS address is 0x380f*/ -#define OV5693_TIMING_VTS_L 0x380f - -#define OV5693_MWB_RED_GAIN_H 0x3400 -#define OV5693_MWB_GREEN_GAIN_H 0x3402 -#define OV5693_MWB_BLUE_GAIN_H 0x3404 -#define OV5693_MWB_GAIN_MAX 0x0fff - -#define OV5693_START_STREAMING 0x01 -#define OV5693_STOP_STREAMING 0x00 - -#define VCM_ADDR 0x0c -#define VCM_CODE_MSB 0x04 - -#define OV5693_INVALID_CONFIG 0xffffffff - -#define OV5693_VCM_SLEW_STEP 0x30F0 -#define OV5693_VCM_SLEW_STEP_MAX 0x7 -#define OV5693_VCM_SLEW_STEP_MASK 0x7 -#define OV5693_VCM_CODE 0x30F2 -#define OV5693_VCM_SLEW_TIME 0x30F4 -#define OV5693_VCM_SLEW_TIME_MAX 0xffff -#define OV5693_VCM_ENABLE 0x8000 - -#define OV5693_VCM_MAX_FOCUS_NEG -1023 -#define OV5693_VCM_MAX_FOCUS_POS 1023 - -#define DLC_ENABLE 1 -#define DLC_DISABLE 0 -#define VCM_PROTECTION_OFF 0xeca3 -#define VCM_PROTECTION_ON 0xdc51 -#define VCM_DEFAULT_S 0x0 -#define vcm_step_s(a) (u8)(a & 0xf) -#define vcm_step_mclk(a) (u8)((a >> 4) & 0x3) -#define vcm_dlc_mclk(dlc, mclk) (u16)((dlc << 3) | mclk | 0xa104) -#define vcm_tsrc(tsrc) (u16)(tsrc << 3 | 0xf200) -#define vcm_val(data, s) (u16)(data << 4 | s) -#define DIRECT_VCM vcm_dlc_mclk(0, 0) - -/* Defines for OTP Data Registers */ -#define OV5693_FRAME_OFF_NUM 0x4202 -#define OV5693_OTP_BYTE_MAX 32 //change to 32 as needed by otpdata -#define OV5693_OTP_SHORT_MAX 16 -#define OV5693_OTP_START_ADDR 0x3D00 -#define OV5693_OTP_END_ADDR 0x3D0F -#define OV5693_OTP_DATA_SIZE 320 -#define OV5693_OTP_PROGRAM_REG 0x3D80 -#define OV5693_OTP_READ_REG 0x3D81 // 1:Enable 0:disable -#define OV5693_OTP_BANK_REG 0x3D84 //otp bank and mode -#define OV5693_OTP_READY_REG_DONE 1 -#define OV5693_OTP_BANK_MAX 28 -#define OV5693_OTP_BANK_SIZE 16 //16 bytes per bank -#define OV5693_OTP_READ_ONETIME 16 -#define OV5693_OTP_MODE_READ 1 - -struct regval_list { - u16 reg_num; - u8 value; -}; - -struct ov5693_resolution { - u8 *desc; - const struct ov5693_reg *regs; - int res; - int width; - int height; - int fps; - int pix_clk_freq; - u16 pixels_per_line; - u16 lines_per_frame; - bool used; -}; - -struct ov5693_format { - u8 *desc; - u32 pixelformat; - struct ov5693_reg *regs; -}; - -enum vcm_type { - VCM_UNKNOWN, - VCM_AD5823, - VCM_DW9714, -}; - -/* - * ov5693 device structure. - */ -struct ov5693_device { - struct v4l2_subdev sd; - struct media_pad pad; - struct v4l2_mbus_framefmt format; - struct mutex input_lock; - struct v4l2_ctrl_handler ctrl_handler; - - struct camera_sensor_platform_data *platform_data; - ktime_t timestamp_t_focus_abs; - int fmt_idx; - int run_mode; - int otp_size; - u8 *otp_data; - u32 focus; - s16 number_of_steps; - u8 res; - u8 type; - bool vcm_update; - enum vcm_type vcm; -}; - -enum ov5693_tok_type { - OV5693_8BIT = 0x0001, - OV5693_16BIT = 0x0002, - OV5693_32BIT = 0x0004, - OV5693_TOK_TERM = 0xf000, /* terminating token for reg list */ - OV5693_TOK_DELAY = 0xfe00, /* delay token for reg list */ - OV5693_TOK_MASK = 0xfff0 -}; - -/** - * struct ov5693_reg - MI sensor register format - * @type: type of the register - * @reg: 16-bit offset to register - * @val: 8/16/32-bit register value - * - * Define a structure for sensor register initialization values - */ -struct ov5693_reg { - enum ov5693_tok_type type; - u16 reg; - u32 val; /* @set value for read/mod/write, @mask */ -}; - -#define to_ov5693_sensor(x) container_of(x, struct ov5693_device, sd) - -#define OV5693_MAX_WRITE_BUF_SIZE 30 - -struct ov5693_write_buffer { - u16 addr; - u8 data[OV5693_MAX_WRITE_BUF_SIZE]; -}; - -struct ov5693_write_ctrl { - int index; - struct ov5693_write_buffer buffer; -}; - -static struct ov5693_reg const ov5693_global_setting[] = { - {OV5693_8BIT, 0x0103, 0x01}, - {OV5693_8BIT, 0x3001, 0x0a}, - {OV5693_8BIT, 0x3002, 0x80}, - {OV5693_8BIT, 0x3006, 0x00}, - {OV5693_8BIT, 0x3011, 0x21}, - {OV5693_8BIT, 0x3012, 0x09}, - {OV5693_8BIT, 0x3013, 0x10}, - {OV5693_8BIT, 0x3014, 0x00}, - {OV5693_8BIT, 0x3015, 0x08}, - {OV5693_8BIT, 0x3016, 0xf0}, - {OV5693_8BIT, 0x3017, 0xf0}, - {OV5693_8BIT, 0x3018, 0xf0}, - {OV5693_8BIT, 0x301b, 0xb4}, - {OV5693_8BIT, 0x301d, 0x02}, - {OV5693_8BIT, 0x3021, 0x00}, - {OV5693_8BIT, 0x3022, 0x01}, - {OV5693_8BIT, 0x3028, 0x44}, - {OV5693_8BIT, 0x3098, 0x02}, - {OV5693_8BIT, 0x3099, 0x19}, - {OV5693_8BIT, 0x309a, 0x02}, - {OV5693_8BIT, 0x309b, 0x01}, - {OV5693_8BIT, 0x309c, 0x00}, - {OV5693_8BIT, 0x30a0, 0xd2}, - {OV5693_8BIT, 0x30a2, 0x01}, - {OV5693_8BIT, 0x30b2, 0x00}, - {OV5693_8BIT, 0x30b3, 0x7d}, - {OV5693_8BIT, 0x30b4, 0x03}, - {OV5693_8BIT, 0x30b5, 0x04}, - {OV5693_8BIT, 0x30b6, 0x01}, - {OV5693_8BIT, 0x3104, 0x21}, - {OV5693_8BIT, 0x3106, 0x00}, - {OV5693_8BIT, 0x3400, 0x04}, - {OV5693_8BIT, 0x3401, 0x00}, - {OV5693_8BIT, 0x3402, 0x04}, - {OV5693_8BIT, 0x3403, 0x00}, - {OV5693_8BIT, 0x3404, 0x04}, - {OV5693_8BIT, 0x3405, 0x00}, - {OV5693_8BIT, 0x3406, 0x01}, - {OV5693_8BIT, 0x3500, 0x00}, - {OV5693_8BIT, 0x3503, 0x07}, - {OV5693_8BIT, 0x3504, 0x00}, - {OV5693_8BIT, 0x3505, 0x00}, - {OV5693_8BIT, 0x3506, 0x00}, - {OV5693_8BIT, 0x3507, 0x02}, - {OV5693_8BIT, 0x3508, 0x00}, - {OV5693_8BIT, 0x3509, 0x10}, - {OV5693_8BIT, 0x350a, 0x00}, - {OV5693_8BIT, 0x350b, 0x40}, - {OV5693_8BIT, 0x3601, 0x0a}, - {OV5693_8BIT, 0x3602, 0x38}, - {OV5693_8BIT, 0x3612, 0x80}, - {OV5693_8BIT, 0x3620, 0x54}, - {OV5693_8BIT, 0x3621, 0xc7}, - {OV5693_8BIT, 0x3622, 0x0f}, - {OV5693_8BIT, 0x3625, 0x10}, - {OV5693_8BIT, 0x3630, 0x55}, - {OV5693_8BIT, 0x3631, 0xf4}, - {OV5693_8BIT, 0x3632, 0x00}, - {OV5693_8BIT, 0x3633, 0x34}, - {OV5693_8BIT, 0x3634, 0x02}, - {OV5693_8BIT, 0x364d, 0x0d}, - {OV5693_8BIT, 0x364f, 0xdd}, - {OV5693_8BIT, 0x3660, 0x04}, - {OV5693_8BIT, 0x3662, 0x10}, - {OV5693_8BIT, 0x3663, 0xf1}, - {OV5693_8BIT, 0x3665, 0x00}, - {OV5693_8BIT, 0x3666, 0x20}, - {OV5693_8BIT, 0x3667, 0x00}, - {OV5693_8BIT, 0x366a, 0x80}, - {OV5693_8BIT, 0x3680, 0xe0}, - {OV5693_8BIT, 0x3681, 0x00}, - {OV5693_8BIT, 0x3700, 0x42}, - {OV5693_8BIT, 0x3701, 0x14}, - {OV5693_8BIT, 0x3702, 0xa0}, - {OV5693_8BIT, 0x3703, 0xd8}, - {OV5693_8BIT, 0x3704, 0x78}, - {OV5693_8BIT, 0x3705, 0x02}, - {OV5693_8BIT, 0x370a, 0x00}, - {OV5693_8BIT, 0x370b, 0x20}, - {OV5693_8BIT, 0x370c, 0x0c}, - {OV5693_8BIT, 0x370d, 0x11}, - {OV5693_8BIT, 0x370e, 0x00}, - {OV5693_8BIT, 0x370f, 0x40}, - {OV5693_8BIT, 0x3710, 0x00}, - {OV5693_8BIT, 0x371a, 0x1c}, - {OV5693_8BIT, 0x371b, 0x05}, - {OV5693_8BIT, 0x371c, 0x01}, - {OV5693_8BIT, 0x371e, 0xa1}, - {OV5693_8BIT, 0x371f, 0x0c}, - {OV5693_8BIT, 0x3721, 0x00}, - {OV5693_8BIT, 0x3724, 0x10}, - {OV5693_8BIT, 0x3726, 0x00}, - {OV5693_8BIT, 0x372a, 0x01}, - {OV5693_8BIT, 0x3730, 0x10}, - {OV5693_8BIT, 0x3738, 0x22}, - {OV5693_8BIT, 0x3739, 0xe5}, - {OV5693_8BIT, 0x373a, 0x50}, - {OV5693_8BIT, 0x373b, 0x02}, - {OV5693_8BIT, 0x373c, 0x41}, - {OV5693_8BIT, 0x373f, 0x02}, - {OV5693_8BIT, 0x3740, 0x42}, - {OV5693_8BIT, 0x3741, 0x02}, - {OV5693_8BIT, 0x3742, 0x18}, - {OV5693_8BIT, 0x3743, 0x01}, - {OV5693_8BIT, 0x3744, 0x02}, - {OV5693_8BIT, 0x3747, 0x10}, - {OV5693_8BIT, 0x374c, 0x04}, - {OV5693_8BIT, 0x3751, 0xf0}, - {OV5693_8BIT, 0x3752, 0x00}, - {OV5693_8BIT, 0x3753, 0x00}, - {OV5693_8BIT, 0x3754, 0xc0}, - {OV5693_8BIT, 0x3755, 0x00}, - {OV5693_8BIT, 0x3756, 0x1a}, - {OV5693_8BIT, 0x3758, 0x00}, - {OV5693_8BIT, 0x3759, 0x0f}, - {OV5693_8BIT, 0x376b, 0x44}, - {OV5693_8BIT, 0x375c, 0x04}, - {OV5693_8BIT, 0x3774, 0x10}, - {OV5693_8BIT, 0x3776, 0x00}, - {OV5693_8BIT, 0x377f, 0x08}, - {OV5693_8BIT, 0x3780, 0x22}, - {OV5693_8BIT, 0x3781, 0x0c}, - {OV5693_8BIT, 0x3784, 0x2c}, - {OV5693_8BIT, 0x3785, 0x1e}, - {OV5693_8BIT, 0x378f, 0xf5}, - {OV5693_8BIT, 0x3791, 0xb0}, - {OV5693_8BIT, 0x3795, 0x00}, - {OV5693_8BIT, 0x3796, 0x64}, - {OV5693_8BIT, 0x3797, 0x11}, - {OV5693_8BIT, 0x3798, 0x30}, - {OV5693_8BIT, 0x3799, 0x41}, - {OV5693_8BIT, 0x379a, 0x07}, - {OV5693_8BIT, 0x379b, 0xb0}, - {OV5693_8BIT, 0x379c, 0x0c}, - {OV5693_8BIT, 0x37c5, 0x00}, - {OV5693_8BIT, 0x37c6, 0x00}, - {OV5693_8BIT, 0x37c7, 0x00}, - {OV5693_8BIT, 0x37c9, 0x00}, - {OV5693_8BIT, 0x37ca, 0x00}, - {OV5693_8BIT, 0x37cb, 0x00}, - {OV5693_8BIT, 0x37de, 0x00}, - {OV5693_8BIT, 0x37df, 0x00}, - {OV5693_8BIT, 0x3800, 0x00}, - {OV5693_8BIT, 0x3801, 0x00}, - {OV5693_8BIT, 0x3802, 0x00}, - {OV5693_8BIT, 0x3804, 0x0a}, - {OV5693_8BIT, 0x3805, 0x3f}, - {OV5693_8BIT, 0x3810, 0x00}, - {OV5693_8BIT, 0x3812, 0x00}, - {OV5693_8BIT, 0x3823, 0x00}, - {OV5693_8BIT, 0x3824, 0x00}, - {OV5693_8BIT, 0x3825, 0x00}, - {OV5693_8BIT, 0x3826, 0x00}, - {OV5693_8BIT, 0x3827, 0x00}, - {OV5693_8BIT, 0x382a, 0x04}, - {OV5693_8BIT, 0x3a04, 0x06}, - {OV5693_8BIT, 0x3a05, 0x14}, - {OV5693_8BIT, 0x3a06, 0x00}, - {OV5693_8BIT, 0x3a07, 0xfe}, - {OV5693_8BIT, 0x3b00, 0x00}, - {OV5693_8BIT, 0x3b02, 0x00}, - {OV5693_8BIT, 0x3b03, 0x00}, - {OV5693_8BIT, 0x3b04, 0x00}, - {OV5693_8BIT, 0x3b05, 0x00}, - {OV5693_8BIT, 0x3e07, 0x20}, - {OV5693_8BIT, 0x4000, 0x08}, - {OV5693_8BIT, 0x4001, 0x04}, - {OV5693_8BIT, 0x4002, 0x45}, - {OV5693_8BIT, 0x4004, 0x08}, - {OV5693_8BIT, 0x4005, 0x18}, - {OV5693_8BIT, 0x4006, 0x20}, - {OV5693_8BIT, 0x4008, 0x24}, - {OV5693_8BIT, 0x4009, 0x10}, - {OV5693_8BIT, 0x400c, 0x00}, - {OV5693_8BIT, 0x400d, 0x00}, - {OV5693_8BIT, 0x4058, 0x00}, - {OV5693_8BIT, 0x404e, 0x37}, - {OV5693_8BIT, 0x404f, 0x8f}, - {OV5693_8BIT, 0x4058, 0x00}, - {OV5693_8BIT, 0x4101, 0xb2}, - {OV5693_8BIT, 0x4303, 0x00}, - {OV5693_8BIT, 0x4304, 0x08}, - {OV5693_8BIT, 0x4307, 0x31}, - {OV5693_8BIT, 0x4311, 0x04}, - {OV5693_8BIT, 0x4315, 0x01}, - {OV5693_8BIT, 0x4511, 0x05}, - {OV5693_8BIT, 0x4512, 0x01}, - {OV5693_8BIT, 0x4806, 0x00}, - {OV5693_8BIT, 0x4816, 0x52}, - {OV5693_8BIT, 0x481f, 0x30}, - {OV5693_8BIT, 0x4826, 0x2c}, - {OV5693_8BIT, 0x4831, 0x64}, - {OV5693_8BIT, 0x4d00, 0x04}, - {OV5693_8BIT, 0x4d01, 0x71}, - {OV5693_8BIT, 0x4d02, 0xfd}, - {OV5693_8BIT, 0x4d03, 0xf5}, - {OV5693_8BIT, 0x4d04, 0x0c}, - {OV5693_8BIT, 0x4d05, 0xcc}, - {OV5693_8BIT, 0x4837, 0x0a}, - {OV5693_8BIT, 0x5000, 0x06}, - {OV5693_8BIT, 0x5001, 0x01}, - {OV5693_8BIT, 0x5003, 0x20}, - {OV5693_8BIT, 0x5046, 0x0a}, - {OV5693_8BIT, 0x5013, 0x00}, - {OV5693_8BIT, 0x5046, 0x0a}, - {OV5693_8BIT, 0x5780, 0x1c}, - {OV5693_8BIT, 0x5786, 0x20}, - {OV5693_8BIT, 0x5787, 0x10}, - {OV5693_8BIT, 0x5788, 0x18}, - {OV5693_8BIT, 0x578a, 0x04}, - {OV5693_8BIT, 0x578b, 0x02}, - {OV5693_8BIT, 0x578c, 0x02}, - {OV5693_8BIT, 0x578e, 0x06}, - {OV5693_8BIT, 0x578f, 0x02}, - {OV5693_8BIT, 0x5790, 0x02}, - {OV5693_8BIT, 0x5791, 0xff}, - {OV5693_8BIT, 0x5842, 0x01}, - {OV5693_8BIT, 0x5843, 0x2b}, - {OV5693_8BIT, 0x5844, 0x01}, - {OV5693_8BIT, 0x5845, 0x92}, - {OV5693_8BIT, 0x5846, 0x01}, - {OV5693_8BIT, 0x5847, 0x8f}, - {OV5693_8BIT, 0x5848, 0x01}, - {OV5693_8BIT, 0x5849, 0x0c}, - {OV5693_8BIT, 0x5e00, 0x00}, - {OV5693_8BIT, 0x5e10, 0x0c}, - {OV5693_8BIT, 0x0100, 0x00}, - {OV5693_TOK_TERM, 0, 0} -}; - -#if ENABLE_NON_PREVIEW -/* - * 654x496 30fps 17ms VBlanking 2lane 10Bit (Scaling) - */ -static struct ov5693_reg const ov5693_654x496[] = { - {OV5693_8BIT, 0x3501, 0x3d}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe6}, - {OV5693_8BIT, 0x3709, 0xc7}, - {OV5693_8BIT, 0x3803, 0x00}, - {OV5693_8BIT, 0x3806, 0x07}, - {OV5693_8BIT, 0x3807, 0xa3}, - {OV5693_8BIT, 0x3808, 0x02}, - {OV5693_8BIT, 0x3809, 0x90}, - {OV5693_8BIT, 0x380a, 0x01}, - {OV5693_8BIT, 0x380b, 0xf0}, - {OV5693_8BIT, 0x380c, 0x0a}, - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3811, 0x08}, - {OV5693_8BIT, 0x3813, 0x02}, - {OV5693_8BIT, 0x3814, 0x31}, - {OV5693_8BIT, 0x3815, 0x31}, - {OV5693_8BIT, 0x3820, 0x04}, - {OV5693_8BIT, 0x3821, 0x1f}, - {OV5693_8BIT, 0x5002, 0x80}, - {OV5693_8BIT, 0x0100, 0x01}, - {OV5693_TOK_TERM, 0, 0} -}; - -/* - * 1296x976 30fps 17ms VBlanking 2lane 10Bit (Scaling) -*DS from 2592x1952 -*/ -static struct ov5693_reg const ov5693_1296x976[] = { - {OV5693_8BIT, 0x3501, 0x7b}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - - {OV5693_8BIT, 0x3800, 0x00}, - {OV5693_8BIT, 0x3801, 0x00}, - {OV5693_8BIT, 0x3802, 0x00}, - {OV5693_8BIT, 0x3803, 0x00}, - - {OV5693_8BIT, 0x3804, 0x0a}, - {OV5693_8BIT, 0x3805, 0x3f}, - {OV5693_8BIT, 0x3806, 0x07}, - {OV5693_8BIT, 0x3807, 0xA3}, - - {OV5693_8BIT, 0x3808, 0x05}, - {OV5693_8BIT, 0x3809, 0x10}, - {OV5693_8BIT, 0x380a, 0x03}, - {OV5693_8BIT, 0x380b, 0xD0}, - - {OV5693_8BIT, 0x380c, 0x0a}, - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, - {OV5693_8BIT, 0x380f, 0xc0}, - - {OV5693_8BIT, 0x3810, 0x00}, - {OV5693_8BIT, 0x3811, 0x10}, - {OV5693_8BIT, 0x3812, 0x00}, - {OV5693_8BIT, 0x3813, 0x02}, - - {OV5693_8BIT, 0x3814, 0x11}, /*X subsample control*/ - {OV5693_8BIT, 0x3815, 0x11}, /*Y subsample control*/ - {OV5693_8BIT, 0x3820, 0x00}, - {OV5693_8BIT, 0x3821, 0x1e}, - {OV5693_8BIT, 0x5002, 0x00}, - {OV5693_8BIT, 0x5041, 0x84}, /* scale is auto enabled */ - {OV5693_8BIT, 0x0100, 0x01}, - {OV5693_TOK_TERM, 0, 0} - -}; - -/* - * 336x256 30fps 17ms VBlanking 2lane 10Bit (Scaling) - DS from 2564x1956 - */ -static struct ov5693_reg const ov5693_336x256[] = { - {OV5693_8BIT, 0x3501, 0x3d}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe6}, - {OV5693_8BIT, 0x3709, 0xc7}, - {OV5693_8BIT, 0x3806, 0x07}, - {OV5693_8BIT, 0x3807, 0xa3}, - {OV5693_8BIT, 0x3808, 0x01}, - {OV5693_8BIT, 0x3809, 0x50}, - {OV5693_8BIT, 0x380a, 0x01}, - {OV5693_8BIT, 0x380b, 0x00}, - {OV5693_8BIT, 0x380c, 0x0a}, - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3811, 0x1E}, - {OV5693_8BIT, 0x3814, 0x31}, - {OV5693_8BIT, 0x3815, 0x31}, - {OV5693_8BIT, 0x3820, 0x04}, - {OV5693_8BIT, 0x3821, 0x1f}, - {OV5693_8BIT, 0x5002, 0x80}, - {OV5693_8BIT, 0x0100, 0x01}, - {OV5693_TOK_TERM, 0, 0} -}; - -/* - * 336x256 30fps 17ms VBlanking 2lane 10Bit (Scaling) - DS from 2368x1956 - */ -static struct ov5693_reg const ov5693_368x304[] = { - {OV5693_8BIT, 0x3501, 0x3d}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe6}, - {OV5693_8BIT, 0x3709, 0xc7}, - {OV5693_8BIT, 0x3808, 0x01}, - {OV5693_8BIT, 0x3809, 0x70}, - {OV5693_8BIT, 0x380a, 0x01}, - {OV5693_8BIT, 0x380b, 0x30}, - {OV5693_8BIT, 0x380c, 0x0a}, - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3811, 0x80}, - {OV5693_8BIT, 0x3814, 0x31}, - {OV5693_8BIT, 0x3815, 0x31}, - {OV5693_8BIT, 0x3820, 0x04}, - {OV5693_8BIT, 0x3821, 0x1f}, - {OV5693_8BIT, 0x5002, 0x80}, - {OV5693_8BIT, 0x0100, 0x01}, - {OV5693_TOK_TERM, 0, 0} -}; - -/* - * ov5693_192x160 30fps 17ms VBlanking 2lane 10Bit (Scaling) - DS from 2460x1956 - */ -static struct ov5693_reg const ov5693_192x160[] = { - {OV5693_8BIT, 0x3501, 0x7b}, - {OV5693_8BIT, 0x3502, 0x80}, - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - {OV5693_8BIT, 0x3804, 0x0a}, - {OV5693_8BIT, 0x3805, 0x3f}, - {OV5693_8BIT, 0x3806, 0x07}, - {OV5693_8BIT, 0x3807, 0xA3}, - {OV5693_8BIT, 0x3808, 0x00}, - {OV5693_8BIT, 0x3809, 0xC0}, - {OV5693_8BIT, 0x380a, 0x00}, - {OV5693_8BIT, 0x380b, 0xA0}, - {OV5693_8BIT, 0x380c, 0x0a}, - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3811, 0x40}, - {OV5693_8BIT, 0x3813, 0x00}, - {OV5693_8BIT, 0x3814, 0x31}, - {OV5693_8BIT, 0x3815, 0x31}, - {OV5693_8BIT, 0x3820, 0x04}, - {OV5693_8BIT, 0x3821, 0x1f}, - {OV5693_8BIT, 0x5002, 0x80}, - {OV5693_8BIT, 0x0100, 0x01}, - {OV5693_TOK_TERM, 0, 0} -}; - -static struct ov5693_reg const ov5693_736x496[] = { - {OV5693_8BIT, 0x3501, 0x3d}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe6}, - {OV5693_8BIT, 0x3709, 0xc7}, - {OV5693_8BIT, 0x3803, 0x68}, - {OV5693_8BIT, 0x3806, 0x07}, - {OV5693_8BIT, 0x3807, 0x3b}, - {OV5693_8BIT, 0x3808, 0x02}, - {OV5693_8BIT, 0x3809, 0xe0}, - {OV5693_8BIT, 0x380a, 0x01}, - {OV5693_8BIT, 0x380b, 0xf0}, - {OV5693_8BIT, 0x380c, 0x0a}, /*hts*/ - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, /*vts*/ - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3811, 0x08}, - {OV5693_8BIT, 0x3813, 0x02}, - {OV5693_8BIT, 0x3814, 0x31}, - {OV5693_8BIT, 0x3815, 0x31}, - {OV5693_8BIT, 0x3820, 0x04}, - {OV5693_8BIT, 0x3821, 0x1f}, - {OV5693_8BIT, 0x5002, 0x80}, - {OV5693_8BIT, 0x0100, 0x01}, - {OV5693_TOK_TERM, 0, 0} -}; -#endif - -/* -static struct ov5693_reg const ov5693_736x496[] = { - {OV5693_8BIT, 0x3501, 0x7b}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe6}, - {OV5693_8BIT, 0x3709, 0xc3}, - {OV5693_8BIT, 0x3803, 0x00}, - {OV5693_8BIT, 0x3806, 0x07}, - {OV5693_8BIT, 0x3807, 0xa3}, - {OV5693_8BIT, 0x3808, 0x02}, - {OV5693_8BIT, 0x3809, 0xe0}, - {OV5693_8BIT, 0x380a, 0x01}, - {OV5693_8BIT, 0x380b, 0xf0}, - {OV5693_8BIT, 0x380c, 0x0d}, - {OV5693_8BIT, 0x380d, 0xb0}, - {OV5693_8BIT, 0x380e, 0x05}, - {OV5693_8BIT, 0x380f, 0xf2}, - {OV5693_8BIT, 0x3811, 0x08}, - {OV5693_8BIT, 0x3813, 0x02}, - {OV5693_8BIT, 0x3814, 0x31}, - {OV5693_8BIT, 0x3815, 0x31}, - {OV5693_8BIT, 0x3820, 0x01}, - {OV5693_8BIT, 0x3821, 0x1f}, - {OV5693_8BIT, 0x5002, 0x00}, - {OV5693_8BIT, 0x0100, 0x01}, - {OV5693_TOK_TERM, 0, 0} -}; -*/ -/* - * 976x556 30fps 8.8ms VBlanking 2lane 10Bit (Scaling) - */ -#if ENABLE_NON_PREVIEW -static struct ov5693_reg const ov5693_976x556[] = { - {OV5693_8BIT, 0x3501, 0x7b}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - {OV5693_8BIT, 0x3803, 0xf0}, - {OV5693_8BIT, 0x3806, 0x06}, - {OV5693_8BIT, 0x3807, 0xa7}, - {OV5693_8BIT, 0x3808, 0x03}, - {OV5693_8BIT, 0x3809, 0xd0}, - {OV5693_8BIT, 0x380a, 0x02}, - {OV5693_8BIT, 0x380b, 0x2C}, - {OV5693_8BIT, 0x380c, 0x0a}, - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3811, 0x10}, - {OV5693_8BIT, 0x3813, 0x02}, - {OV5693_8BIT, 0x3814, 0x11}, - {OV5693_8BIT, 0x3815, 0x11}, - {OV5693_8BIT, 0x3820, 0x00}, - {OV5693_8BIT, 0x3821, 0x1e}, - {OV5693_8BIT, 0x5002, 0x80}, - {OV5693_8BIT, 0x0100, 0x01}, - {OV5693_TOK_TERM, 0, 0} -}; - -/*DS from 2624x1492*/ -static struct ov5693_reg const ov5693_1296x736[] = { - {OV5693_8BIT, 0x3501, 0x7b}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - - {OV5693_8BIT, 0x3800, 0x00}, - {OV5693_8BIT, 0x3801, 0x00}, - {OV5693_8BIT, 0x3802, 0x00}, - {OV5693_8BIT, 0x3803, 0x00}, - - {OV5693_8BIT, 0x3804, 0x0a}, - {OV5693_8BIT, 0x3805, 0x3f}, - {OV5693_8BIT, 0x3806, 0x07}, - {OV5693_8BIT, 0x3807, 0xA3}, - - {OV5693_8BIT, 0x3808, 0x05}, - {OV5693_8BIT, 0x3809, 0x10}, - {OV5693_8BIT, 0x380a, 0x02}, - {OV5693_8BIT, 0x380b, 0xe0}, - - {OV5693_8BIT, 0x380c, 0x0a}, - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, - {OV5693_8BIT, 0x380f, 0xc0}, - - {OV5693_8BIT, 0x3813, 0xE8}, - - {OV5693_8BIT, 0x3814, 0x11}, /*X subsample control*/ - {OV5693_8BIT, 0x3815, 0x11}, /*Y subsample control*/ - {OV5693_8BIT, 0x3820, 0x00}, - {OV5693_8BIT, 0x3821, 0x1e}, - {OV5693_8BIT, 0x5002, 0x00}, - {OV5693_8BIT, 0x5041, 0x84}, /* scale is auto enabled */ - {OV5693_8BIT, 0x0100, 0x01}, - {OV5693_TOK_TERM, 0, 0} -}; - -static struct ov5693_reg const ov5693_1636p_30fps[] = { - {OV5693_8BIT, 0x3501, 0x7b}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - {OV5693_8BIT, 0x3803, 0xf0}, - {OV5693_8BIT, 0x3806, 0x06}, - {OV5693_8BIT, 0x3807, 0xa7}, - {OV5693_8BIT, 0x3808, 0x06}, - {OV5693_8BIT, 0x3809, 0x64}, - {OV5693_8BIT, 0x380a, 0x04}, - {OV5693_8BIT, 0x380b, 0x48}, - {OV5693_8BIT, 0x380c, 0x0a}, /*hts*/ - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, /*vts*/ - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3811, 0x02}, - {OV5693_8BIT, 0x3813, 0x02}, - {OV5693_8BIT, 0x3814, 0x11}, - {OV5693_8BIT, 0x3815, 0x11}, - {OV5693_8BIT, 0x3820, 0x00}, - {OV5693_8BIT, 0x3821, 0x1e}, - {OV5693_8BIT, 0x5002, 0x80}, - {OV5693_8BIT, 0x0100, 0x01}, - {OV5693_TOK_TERM, 0, 0} -}; -#endif - -static struct ov5693_reg const ov5693_1616x1216_30fps[] = { - {OV5693_8BIT, 0x3501, 0x7b}, - {OV5693_8BIT, 0x3502, 0x80}, - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - {OV5693_8BIT, 0x3800, 0x00}, /*{3800,3801} Array X start*/ - {OV5693_8BIT, 0x3801, 0x08}, /* 04 //{3800,3801} Array X start*/ - {OV5693_8BIT, 0x3802, 0x00}, /*{3802,3803} Array Y start*/ - {OV5693_8BIT, 0x3803, 0x04}, /* 00 //{3802,3803} Array Y start*/ - {OV5693_8BIT, 0x3804, 0x0a}, /*{3804,3805} Array X end*/ - {OV5693_8BIT, 0x3805, 0x37}, /* 3b //{3804,3805} Array X end*/ - {OV5693_8BIT, 0x3806, 0x07}, /*{3806,3807} Array Y end*/ - {OV5693_8BIT, 0x3807, 0x9f}, /* a3 //{3806,3807} Array Y end*/ - {OV5693_8BIT, 0x3808, 0x06}, /*{3808,3809} Final output H size*/ - {OV5693_8BIT, 0x3809, 0x50}, /*{3808,3809} Final output H size*/ - {OV5693_8BIT, 0x380a, 0x04}, /*{380a,380b} Final output V size*/ - {OV5693_8BIT, 0x380b, 0xc0}, /*{380a,380b} Final output V size*/ - {OV5693_8BIT, 0x380c, 0x0a}, /*{380c,380d} HTS*/ - {OV5693_8BIT, 0x380d, 0x80}, /*{380c,380d} HTS*/ - {OV5693_8BIT, 0x380e, 0x07}, /*{380e,380f} VTS*/ - {OV5693_8BIT, 0x380f, 0xc0}, /* bc //{380e,380f} VTS*/ - {OV5693_8BIT, 0x3810, 0x00}, /*{3810,3811} windowing X offset*/ - {OV5693_8BIT, 0x3811, 0x10}, /*{3810,3811} windowing X offset*/ - {OV5693_8BIT, 0x3812, 0x00}, /*{3812,3813} windowing Y offset*/ - {OV5693_8BIT, 0x3813, 0x06}, /*{3812,3813} windowing Y offset*/ - {OV5693_8BIT, 0x3814, 0x11}, /*X subsample control*/ - {OV5693_8BIT, 0x3815, 0x11}, /*Y subsample control*/ - {OV5693_8BIT, 0x3820, 0x00}, /*FLIP/Binning control*/ - {OV5693_8BIT, 0x3821, 0x1e}, /*MIRROR control*/ - {OV5693_8BIT, 0x5002, 0x00}, - {OV5693_8BIT, 0x5041, 0x84}, - {OV5693_8BIT, 0x0100, 0x01}, - {OV5693_TOK_TERM, 0, 0} -}; - -/* - * 1940x1096 30fps 8.8ms VBlanking 2lane 10bit (Scaling) - */ -#if ENABLE_NON_PREVIEW -static struct ov5693_reg const ov5693_1940x1096[] = { - {OV5693_8BIT, 0x3501, 0x7b}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - {OV5693_8BIT, 0x3803, 0xf0}, - {OV5693_8BIT, 0x3806, 0x06}, - {OV5693_8BIT, 0x3807, 0xa7}, - {OV5693_8BIT, 0x3808, 0x07}, - {OV5693_8BIT, 0x3809, 0x94}, - {OV5693_8BIT, 0x380a, 0x04}, - {OV5693_8BIT, 0x380b, 0x48}, - {OV5693_8BIT, 0x380c, 0x0a}, - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3811, 0x02}, - {OV5693_8BIT, 0x3813, 0x02}, - {OV5693_8BIT, 0x3814, 0x11}, - {OV5693_8BIT, 0x3815, 0x11}, - {OV5693_8BIT, 0x3820, 0x00}, - {OV5693_8BIT, 0x3821, 0x1e}, - {OV5693_8BIT, 0x5002, 0x80}, - {OV5693_8BIT, 0x0100, 0x01}, - {OV5693_TOK_TERM, 0, 0} -}; - -static struct ov5693_reg const ov5693_2592x1456_30fps[] = { - {OV5693_8BIT, 0x3501, 0x7b}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - {OV5693_8BIT, 0x3800, 0x00}, - {OV5693_8BIT, 0x3801, 0x00}, - {OV5693_8BIT, 0x3802, 0x00}, - {OV5693_8BIT, 0x3803, 0xf0}, - {OV5693_8BIT, 0x3804, 0x0a}, - {OV5693_8BIT, 0x3805, 0x3f}, - {OV5693_8BIT, 0x3806, 0x06}, - {OV5693_8BIT, 0x3807, 0xa4}, - {OV5693_8BIT, 0x3808, 0x0a}, - {OV5693_8BIT, 0x3809, 0x20}, - {OV5693_8BIT, 0x380a, 0x05}, - {OV5693_8BIT, 0x380b, 0xb0}, - {OV5693_8BIT, 0x380c, 0x0a}, - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3811, 0x10}, - {OV5693_8BIT, 0x3813, 0x00}, - {OV5693_8BIT, 0x3814, 0x11}, - {OV5693_8BIT, 0x3815, 0x11}, - {OV5693_8BIT, 0x3820, 0x00}, - {OV5693_8BIT, 0x3821, 0x1e}, - {OV5693_8BIT, 0x5002, 0x00}, - {OV5693_TOK_TERM, 0, 0} -}; -#endif - -static struct ov5693_reg const ov5693_2576x1456_30fps[] = { - {OV5693_8BIT, 0x3501, 0x7b}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - {OV5693_8BIT, 0x3800, 0x00}, - {OV5693_8BIT, 0x3801, 0x00}, - {OV5693_8BIT, 0x3802, 0x00}, - {OV5693_8BIT, 0x3803, 0xf0}, - {OV5693_8BIT, 0x3804, 0x0a}, - {OV5693_8BIT, 0x3805, 0x3f}, - {OV5693_8BIT, 0x3806, 0x06}, - {OV5693_8BIT, 0x3807, 0xa4}, - {OV5693_8BIT, 0x3808, 0x0a}, - {OV5693_8BIT, 0x3809, 0x10}, - {OV5693_8BIT, 0x380a, 0x05}, - {OV5693_8BIT, 0x380b, 0xb0}, - {OV5693_8BIT, 0x380c, 0x0a}, - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3811, 0x18}, - {OV5693_8BIT, 0x3813, 0x00}, - {OV5693_8BIT, 0x3814, 0x11}, - {OV5693_8BIT, 0x3815, 0x11}, - {OV5693_8BIT, 0x3820, 0x00}, - {OV5693_8BIT, 0x3821, 0x1e}, - {OV5693_8BIT, 0x5002, 0x00}, - {OV5693_TOK_TERM, 0, 0} -}; - -/* - * 2592x1944 30fps 0.6ms VBlanking 2lane 10Bit - */ -#if ENABLE_NON_PREVIEW -static struct ov5693_reg const ov5693_2592x1944_30fps[] = { - {OV5693_8BIT, 0x3501, 0x7b}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - {OV5693_8BIT, 0x3803, 0x00}, - {OV5693_8BIT, 0x3806, 0x07}, - {OV5693_8BIT, 0x3807, 0xa3}, - {OV5693_8BIT, 0x3808, 0x0a}, - {OV5693_8BIT, 0x3809, 0x20}, - {OV5693_8BIT, 0x380a, 0x07}, - {OV5693_8BIT, 0x380b, 0x98}, - {OV5693_8BIT, 0x380c, 0x0a}, - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3811, 0x10}, - {OV5693_8BIT, 0x3813, 0x00}, - {OV5693_8BIT, 0x3814, 0x11}, - {OV5693_8BIT, 0x3815, 0x11}, - {OV5693_8BIT, 0x3820, 0x00}, - {OV5693_8BIT, 0x3821, 0x1e}, - {OV5693_8BIT, 0x5002, 0x00}, - {OV5693_8BIT, 0x0100, 0x01}, - {OV5693_TOK_TERM, 0, 0} -}; -#endif - -/* - * 11:9 Full FOV Output, expected FOV Res: 2346x1920 - * ISP Effect Res: 1408x1152 - * Sensor out: 1424x1168, DS From: 2380x1952 - * - * WA: Left Offset: 8, Hor scal: 64 - */ -#if ENABLE_NON_PREVIEW -static struct ov5693_reg const ov5693_1424x1168_30fps[] = { - {OV5693_8BIT, 0x3501, 0x3b}, /* long exposure[15:8] */ - {OV5693_8BIT, 0x3502, 0x80}, /* long exposure[7:0] */ - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - {OV5693_8BIT, 0x3800, 0x00}, /* TIMING_X_ADDR_START */ - {OV5693_8BIT, 0x3801, 0x50}, /* 80 */ - {OV5693_8BIT, 0x3802, 0x00}, /* TIMING_Y_ADDR_START */ - {OV5693_8BIT, 0x3803, 0x02}, /* 2 */ - {OV5693_8BIT, 0x3804, 0x09}, /* TIMING_X_ADDR_END */ - {OV5693_8BIT, 0x3805, 0xdd}, /* 2525 */ - {OV5693_8BIT, 0x3806, 0x07}, /* TIMING_Y_ADDR_END */ - {OV5693_8BIT, 0x3807, 0xa1}, /* 1953 */ - {OV5693_8BIT, 0x3808, 0x05}, /* TIMING_X_OUTPUT_SIZE */ - {OV5693_8BIT, 0x3809, 0x90}, /* 1424 */ - {OV5693_8BIT, 0x380a, 0x04}, /* TIMING_Y_OUTPUT_SIZE */ - {OV5693_8BIT, 0x380b, 0x90}, /* 1168 */ - {OV5693_8BIT, 0x380c, 0x0a}, /* TIMING_HTS */ - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, /* TIMING_VTS */ - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3810, 0x00}, /* TIMING_ISP_X_WIN */ - {OV5693_8BIT, 0x3811, 0x02}, /* 2 */ - {OV5693_8BIT, 0x3812, 0x00}, /* TIMING_ISP_Y_WIN */ - {OV5693_8BIT, 0x3813, 0x00}, /* 0 */ - {OV5693_8BIT, 0x3814, 0x11}, /* TIME_X_INC */ - {OV5693_8BIT, 0x3815, 0x11}, /* TIME_Y_INC */ - {OV5693_8BIT, 0x3820, 0x00}, - {OV5693_8BIT, 0x3821, 0x1e}, - {OV5693_8BIT, 0x5002, 0x00}, - {OV5693_8BIT, 0x5041, 0x84}, /* scale is auto enabled */ - {OV5693_8BIT, 0x0100, 0x01}, - {OV5693_TOK_TERM, 0, 0} -}; -#endif - -/* - * 3:2 Full FOV Output, expected FOV Res: 2560x1706 - * ISP Effect Res: 720x480 - * Sensor out: 736x496, DS From 2616x1764 - */ -static struct ov5693_reg const ov5693_736x496_30fps[] = { - {OV5693_8BIT, 0x3501, 0x3b}, /* long exposure[15:8] */ - {OV5693_8BIT, 0x3502, 0x80}, /* long exposure[7:0] */ - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - {OV5693_8BIT, 0x3800, 0x00}, /* TIMING_X_ADDR_START */ - {OV5693_8BIT, 0x3801, 0x02}, /* 2 */ - {OV5693_8BIT, 0x3802, 0x00}, /* TIMING_Y_ADDR_START */ - {OV5693_8BIT, 0x3803, 0x62}, /* 98 */ - {OV5693_8BIT, 0x3804, 0x0a}, /* TIMING_X_ADDR_END */ - {OV5693_8BIT, 0x3805, 0x3b}, /* 2619 */ - {OV5693_8BIT, 0x3806, 0x07}, /* TIMING_Y_ADDR_END */ - {OV5693_8BIT, 0x3807, 0x43}, /* 1859 */ - {OV5693_8BIT, 0x3808, 0x02}, /* TIMING_X_OUTPUT_SIZE */ - {OV5693_8BIT, 0x3809, 0xe0}, /* 736 */ - {OV5693_8BIT, 0x380a, 0x01}, /* TIMING_Y_OUTPUT_SIZE */ - {OV5693_8BIT, 0x380b, 0xf0}, /* 496 */ - {OV5693_8BIT, 0x380c, 0x0a}, /* TIMING_HTS */ - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, /* TIMING_VTS */ - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3810, 0x00}, /* TIMING_ISP_X_WIN */ - {OV5693_8BIT, 0x3811, 0x02}, /* 2 */ - {OV5693_8BIT, 0x3812, 0x00}, /* TIMING_ISP_Y_WIN */ - {OV5693_8BIT, 0x3813, 0x00}, /* 0 */ - {OV5693_8BIT, 0x3814, 0x11}, /* TIME_X_INC */ - {OV5693_8BIT, 0x3815, 0x11}, /* TIME_Y_INC */ - {OV5693_8BIT, 0x3820, 0x00}, - {OV5693_8BIT, 0x3821, 0x1e}, - {OV5693_8BIT, 0x5002, 0x00}, - {OV5693_8BIT, 0x5041, 0x84}, /* scale is auto enabled */ - {OV5693_8BIT, 0x0100, 0x01}, - {OV5693_TOK_TERM, 0, 0} -}; - -static struct ov5693_reg const ov5693_2576x1936_30fps[] = { - {OV5693_8BIT, 0x3501, 0x7b}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - {OV5693_8BIT, 0x3803, 0x00}, - {OV5693_8BIT, 0x3806, 0x07}, - {OV5693_8BIT, 0x3807, 0xa3}, - {OV5693_8BIT, 0x3808, 0x0a}, - {OV5693_8BIT, 0x3809, 0x10}, - {OV5693_8BIT, 0x380a, 0x07}, - {OV5693_8BIT, 0x380b, 0x90}, - {OV5693_8BIT, 0x380c, 0x0a}, - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3811, 0x18}, - {OV5693_8BIT, 0x3813, 0x00}, - {OV5693_8BIT, 0x3814, 0x11}, - {OV5693_8BIT, 0x3815, 0x11}, - {OV5693_8BIT, 0x3820, 0x00}, - {OV5693_8BIT, 0x3821, 0x1e}, - {OV5693_8BIT, 0x5002, 0x00}, - {OV5693_8BIT, 0x0100, 0x01}, - {OV5693_TOK_TERM, 0, 0} -}; - -static struct ov5693_resolution ov5693_res_preview[] = { - { - .desc = "ov5693_736x496_30fps", - .width = 736, - .height = 496, - .pix_clk_freq = 160, - .fps = 30, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .regs = ov5693_736x496_30fps, - }, - { - .desc = "ov5693_1616x1216_30fps", - .width = 1616, - .height = 1216, - .pix_clk_freq = 160, - .fps = 30, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .regs = ov5693_1616x1216_30fps, - }, - { - .desc = "ov5693_5M_30fps", - .width = 2576, - .height = 1456, - .pix_clk_freq = 160, - .fps = 30, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .regs = ov5693_2576x1456_30fps, - }, - { - .desc = "ov5693_5M_30fps", - .width = 2576, - .height = 1936, - .pix_clk_freq = 160, - .fps = 30, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .regs = ov5693_2576x1936_30fps, - }, -}; - -#define N_RES_PREVIEW (ARRAY_SIZE(ov5693_res_preview)) - -/* - * Disable non-preview configurations until the configuration selection is - * improved. - */ -#if ENABLE_NON_PREVIEW -struct ov5693_resolution ov5693_res_still[] = { - { - .desc = "ov5693_736x496_30fps", - .width = 736, - .height = 496, - .pix_clk_freq = 160, - .fps = 30, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .regs = ov5693_736x496_30fps, - }, - { - .desc = "ov5693_1424x1168_30fps", - .width = 1424, - .height = 1168, - .pix_clk_freq = 160, - .fps = 30, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .regs = ov5693_1424x1168_30fps, - }, - { - .desc = "ov5693_1616x1216_30fps", - .width = 1616, - .height = 1216, - .pix_clk_freq = 160, - .fps = 30, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .regs = ov5693_1616x1216_30fps, - }, - { - .desc = "ov5693_5M_30fps", - .width = 2592, - .height = 1456, - .pix_clk_freq = 160, - .fps = 30, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .regs = ov5693_2592x1456_30fps, - }, - { - .desc = "ov5693_5M_30fps", - .width = 2592, - .height = 1944, - .pix_clk_freq = 160, - .fps = 30, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .regs = ov5693_2592x1944_30fps, - }, -}; - -#define N_RES_STILL (ARRAY_SIZE(ov5693_res_still)) - -struct ov5693_resolution ov5693_res_video[] = { - { - .desc = "ov5693_736x496_30fps", - .width = 736, - .height = 496, - .fps = 30, - .pix_clk_freq = 160, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .regs = ov5693_736x496, - }, - { - .desc = "ov5693_336x256_30fps", - .width = 336, - .height = 256, - .fps = 30, - .pix_clk_freq = 160, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .regs = ov5693_336x256, - }, - { - .desc = "ov5693_368x304_30fps", - .width = 368, - .height = 304, - .fps = 30, - .pix_clk_freq = 160, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .regs = ov5693_368x304, - }, - { - .desc = "ov5693_192x160_30fps", - .width = 192, - .height = 160, - .fps = 30, - .pix_clk_freq = 160, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .regs = ov5693_192x160, - }, - { - .desc = "ov5693_1296x736_30fps", - .width = 1296, - .height = 736, - .fps = 30, - .pix_clk_freq = 160, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .regs = ov5693_1296x736, - }, - { - .desc = "ov5693_1296x976_30fps", - .width = 1296, - .height = 976, - .fps = 30, - .pix_clk_freq = 160, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .regs = ov5693_1296x976, - }, - { - .desc = "ov5693_1636P_30fps", - .width = 1636, - .height = 1096, - .fps = 30, - .pix_clk_freq = 160, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .regs = ov5693_1636p_30fps, - }, - { - .desc = "ov5693_1080P_30fps", - .width = 1940, - .height = 1096, - .fps = 30, - .pix_clk_freq = 160, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .regs = ov5693_1940x1096, - }, - { - .desc = "ov5693_5M_30fps", - .width = 2592, - .height = 1456, - .pix_clk_freq = 160, - .fps = 30, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .regs = ov5693_2592x1456_30fps, - }, - { - .desc = "ov5693_5M_30fps", - .width = 2592, - .height = 1944, - .pix_clk_freq = 160, - .fps = 30, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .regs = ov5693_2592x1944_30fps, - }, -}; - -#define N_RES_VIDEO (ARRAY_SIZE(ov5693_res_video)) -#endif - -static struct ov5693_resolution *ov5693_res = ov5693_res_preview; -static unsigned long N_RES = N_RES_PREVIEW; -#endif -- GitLab From 0301a15a42f2e414d6f628fb51821a186cbfbbbf Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 26 Sep 2023 11:27:09 +0200 Subject: [PATCH 0365/1451] media: atomisp: fix 'read beyond size of field' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If CONFIG_FORTIFY_SOURCE=y, then this warning is produced: In file included from ./include/linux/string.h:254, from ./include/linux/bitmap.h:11, from ./include/linux/cpumask.h:12, from ./arch/x86/include/asm/cpumask.h:5, from ./arch/x86/include/asm/msr.h:11, from ./arch/x86/include/asm/processor.h:23, from ./arch/x86/include/asm/cpufeature.h:5, from ./arch/x86/include/asm/thread_info.h:53, from ./include/linux/thread_info.h:60, from ./arch/x86/include/asm/preempt.h:9, from ./include/linux/preempt.h:79, from ./include/linux/spinlock.h:56, from ./include/linux/mmzone.h:8, from ./include/linux/gfp.h:7, from ./include/linux/slab.h:16, from ./drivers/staging/media/atomisp//include/hmm/hmm.h:26, from drivers/staging/media/atomisp/pci/sh_css_params.c:26: In function ‘fortify_memcpy_chk’, inlined from ‘sh_css_store_sp_group_to_ddr’ at drivers/staging/media/atomisp/pci/sh_css_params.c:3736:3: ./include/linux/fortify-string.h:592:25: warning: call to ‘__read_overflow2_field’ declared with attribute warning: detected read beyond size of field (2nd parameter); maybe use struct_group()? [-Wattribute-warning] 592 | __read_overflow2_field(q_size_field, size); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The reason is that the memcpy copies two fields (each a u8), when the source pointer points to the first field. It's a bit unexpected, so just make this explicit. Signed-off-by: Hans Verkuil Reviewed-by: Hans de Goede --- drivers/staging/media/atomisp/pci/sh_css_params.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css_params.c b/drivers/staging/media/atomisp/pci/sh_css_params.c index 5667e855da766..232744973ab88 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_params.c +++ b/drivers/staging/media/atomisp/pci/sh_css_params.c @@ -3733,8 +3733,8 @@ ia_css_ptr sh_css_store_sp_group_to_ddr(void) if (IS_ISP2401) { memcpy(buf_ptr, &sh_css_sp_group.config, 3); buf_ptr += 3; - memcpy(buf_ptr, &sh_css_sp_group.config.enable_isys_event_queue, 2); - buf_ptr += 2; + *buf_ptr++ = sh_css_sp_group.config.enable_isys_event_queue; + *buf_ptr++ = sh_css_sp_group.config.disable_cont_vf; memset(buf_ptr, 0, 3); buf_ptr += 3; /* Padding 3 bytes for struct sh_css_sp_config*/ } else { -- GitLab From 41c4c6fd8116f67cfd3e862d00ee11bcceece244 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:20:45 +0200 Subject: [PATCH 0366/1451] media: allegro-dvt: increase buffer size in msg_type_name() Fixes this compile error drivers/media/platform/allegro-dvt/allegro-mail.c: In function 'msg_type_name': drivers/media/platform/allegro-dvt/allegro-mail.c:37:48: warning: '%04x' directive output may be truncated writing between 4 and 8 bytes into a region of size 6 [-Wformat-truncation=] 37 | snprintf(buf, sizeof(buf), "(0x%04x)", type); | ^~~~ drivers/media/platform/allegro-dvt/allegro-mail.c:37:44: note: directive argument in the range [1, 4294967295] 37 | snprintf(buf, sizeof(buf), "(0x%04x)", type); | ^~~~~~~~~~ drivers/media/platform/allegro-dvt/allegro-mail.c:37:17: note: 'snprintf' output between 9 and 13 bytes into a destination of size 9 37 | snprintf(buf, sizeof(buf), "(0x%04x)", type); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Hans Verkuil Reviewed-by: Michael Tretter Acked-by: Arnd Bergmann --- drivers/media/platform/allegro-dvt/allegro-mail.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/allegro-dvt/allegro-mail.c b/drivers/media/platform/allegro-dvt/allegro-mail.c index 16effad107469..aadc947a77ae0 100644 --- a/drivers/media/platform/allegro-dvt/allegro-mail.c +++ b/drivers/media/platform/allegro-dvt/allegro-mail.c @@ -16,7 +16,7 @@ const char *msg_type_name(enum mcu_msg_type type) { - static char buf[9]; + static char buf[13]; switch (type) { case MCU_MSG_TYPE_INIT: -- GitLab From 94451182166ae92a28eb79a3e02c75542f1807d8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:20:46 +0200 Subject: [PATCH 0367/1451] media: cadence: increase buffer size in csi2tx_get_resources() Fixes this compiler warning: drivers/media/platform/cadence/cdns-csi2tx.c: In function 'csi2tx_get_resources': drivers/media/platform/cadence/cdns-csi2tx.c:485:63: warning: '%u' directive output may be truncated writing between 1 and 10 bytes into a region of size 8 [-Wformat-truncation=] 485 | snprintf(clk_name, sizeof(clk_name), "pixel_if%u_clk", i); | ^~ drivers/media/platform/cadence/cdns-csi2tx.c:485:54: note: directive argument in the range [0, 4294967294] 485 | snprintf(clk_name, sizeof(clk_name), "pixel_if%u_clk", i); | ^~~~~~~~~~~~~~~~ drivers/media/platform/cadence/cdns-csi2tx.c:485:17: note: 'snprintf' output between 14 and 23 bytes into a destination of size 16 485 | snprintf(clk_name, sizeof(clk_name), "pixel_if%u_clk", i); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Hans Verkuil Acked-by: Maxime Ripard Acked-by: Arnd Bergmann --- drivers/media/platform/cadence/cdns-csi2tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/cadence/cdns-csi2tx.c b/drivers/media/platform/cadence/cdns-csi2tx.c index 1e0400b7803e9..cbbb775201126 100644 --- a/drivers/media/platform/cadence/cdns-csi2tx.c +++ b/drivers/media/platform/cadence/cdns-csi2tx.c @@ -480,7 +480,7 @@ static int csi2tx_get_resources(struct csi2tx_priv *csi2tx, csi2tx->has_internal_dphy = !!(dev_cfg & CSI2TX_DEVICE_CONFIG_HAS_DPHY); for (i = 0; i < csi2tx->max_streams; i++) { - char clk_name[16]; + char clk_name[23]; snprintf(clk_name, sizeof(clk_name), "pixel_if%u_clk", i); csi2tx->pixel_clk[i] = devm_clk_get(&pdev->dev, clk_name); -- GitLab From f55254c96a85f43261f9952c74a7461752964dfc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:20:47 +0200 Subject: [PATCH 0368/1451] media: atomisp: ia_ccs_debug.c: increase enable_info buffer Fixes these compiler warnings: drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c: In function 'ia_css_debug_pipe_graph_dump_stage': drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c:2786:66: warning: '\n' directive output may be truncated writing 2 bytes into a region of size between 0 and 198 [-Wformat-truncation=] 2786 | "%s\\n%s\\n%s", | ^~~ drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c:2785:49: note: 'snprintf' output between 5 and 302 bytes into a destination of size 200 2785 | snprintf(enable_info, sizeof(enable_info), | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2786 | "%s\\n%s\\n%s", | ~~~~~~~~~~~~~~~ 2787 | enable_info1, enable_info2, | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2788 | enable_info3); | ~~~~~~~~~~~~~ drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c:2772:66: warning: '\n' directive output may be truncated writing 2 bytes into a region of size between 0 and 198 [-Wformat-truncation=] 2772 | "%s\\n%s\\n%s", | ^~~ drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c:2771:49: note: 'snprintf' output between 5 and 302 bytes into a destination of size 200 2771 | snprintf(enable_info, sizeof(enable_info), | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2772 | "%s\\n%s\\n%s", | ~~~~~~~~~~~~~~~ 2773 | enable_info1, enable_info2, | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2774 | enable_info3); | ~~~~~~~~~~~~~ drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c:2749:92: warning: 'snprintf' output may be truncated before the last format character [-Wformat-truncation=] 2749 | snprintf(enable_info, sizeof(enable_info), "%s\\n%s", | ^ drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c:2749:41: note: 'snprintf' output between 3 and 201 bytes into a destination of size 200 2749 | snprintf(enable_info, sizeof(enable_info), "%s\\n%s", | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2750 | enable_info1, enable_info2); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Hans Verkuil Reviewed-by: Hans de Goede Acked-by: Arnd Bergmann --- .../staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c index 321485f75fb5f..3e92794555ec7 100644 --- a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c +++ b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c @@ -1206,7 +1206,7 @@ ia_css_debug_pipe_graph_dump_stage( char enable_info1[100]; char enable_info2[100]; char enable_info3[100]; - char enable_info[200]; + char enable_info[302]; struct ia_css_binary_info *bi = stage->binary_info; /* Split it in 2 function-calls to keep the amount of -- GitLab From 4567ebf8e8f9546b373e78e3b7d584cc30b62028 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:20:48 +0200 Subject: [PATCH 0369/1451] media: vivid: avoid integer overflow Fixes these compiler warnings: drivers/media/test-drivers/vivid/vivid-rds-gen.c: In function 'vivid_rds_gen_fill': drivers/media/test-drivers/vivid/vivid-rds-gen.c:147:56: warning: '.' directive output may be truncated writing 1 byte into a region of size between 0 and 3 [-Wformat-truncation=] 147 | snprintf(rds->psname, sizeof(rds->psname), "%6d.%1d", | ^ drivers/media/test-drivers/vivid/vivid-rds-gen.c:147:52: note: directive argument in the range [0, 9] 147 | snprintf(rds->psname, sizeof(rds->psname), "%6d.%1d", | ^~~~~~~~~ drivers/media/test-drivers/vivid/vivid-rds-gen.c:147:9: note: 'snprintf' output between 9 and 12 bytes into a destination of size 9 147 | snprintf(rds->psname, sizeof(rds->psname), "%6d.%1d", | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 148 | freq / 16, ((freq & 0xf) * 10) / 16); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Hans Verkuil Acked-by: Arnd Bergmann --- drivers/media/test-drivers/vivid/vivid-rds-gen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/test-drivers/vivid/vivid-rds-gen.c b/drivers/media/test-drivers/vivid/vivid-rds-gen.c index b5b104ee64c99..c57771119a34b 100644 --- a/drivers/media/test-drivers/vivid/vivid-rds-gen.c +++ b/drivers/media/test-drivers/vivid/vivid-rds-gen.c @@ -145,7 +145,7 @@ void vivid_rds_gen_fill(struct vivid_rds_gen *rds, unsigned freq, rds->ta = alt; rds->ms = true; snprintf(rds->psname, sizeof(rds->psname), "%6d.%1d", - freq / 16, ((freq & 0xf) * 10) / 16); + (freq / 16) % 1000000, (((freq & 0xf) * 10) / 16) % 10); if (alt) strscpy(rds->radiotext, " The Radio Data System can switch between different Radio Texts ", -- GitLab From 83d0d4cc1423194b580356966107379490edd02e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:20:49 +0200 Subject: [PATCH 0370/1451] media: ipu-bridge: increase sensor_name size Fixes this compiler warning: In file included from include/linux/property.h:14, from include/linux/acpi.h:16, from drivers/media/pci/intel/ipu-bridge.c:4: In function 'ipu_bridge_init_swnode_names', inlined from 'ipu_bridge_create_connection_swnodes' at drivers/media/pci/intel/ipu-bridge.c:445:2, inlined from 'ipu_bridge_connect_sensor' at drivers/media/pci/intel/ipu-bridge.c:656:3: include/linux/fwnode.h:81:49: warning: '%u' directive output may be truncated writing between 1 and 3 bytes into a region of size 2 [-Wformat-truncation=] 81 | #define SWNODE_GRAPH_PORT_NAME_FMT "port@%u" | ^~~~~~~~~ drivers/media/pci/intel/ipu-bridge.c:384:18: note: in expansion of macro 'SWNODE_GRAPH_PORT_NAME_FMT' 384 | SWNODE_GRAPH_PORT_NAME_FMT, sensor->link); | ^~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/fwnode.h: In function 'ipu_bridge_connect_sensor': include/linux/fwnode.h:81:55: note: format string is defined here 81 | #define SWNODE_GRAPH_PORT_NAME_FMT "port@%u" | ^~ In function 'ipu_bridge_init_swnode_names', inlined from 'ipu_bridge_create_connection_swnodes' at drivers/media/pci/intel/ipu-bridge.c:445:2, inlined from 'ipu_bridge_connect_sensor' at drivers/media/pci/intel/ipu-bridge.c:656:3: include/linux/fwnode.h:81:49: note: directive argument in the range [0, 255] 81 | #define SWNODE_GRAPH_PORT_NAME_FMT "port@%u" | ^~~~~~~~~ drivers/media/pci/intel/ipu-bridge.c:384:18: note: in expansion of macro 'SWNODE_GRAPH_PORT_NAME_FMT' 384 | SWNODE_GRAPH_PORT_NAME_FMT, sensor->link); | ^~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/media/pci/intel/ipu-bridge.c:382:9: note: 'snprintf' output between 7 and 9 bytes into a destination of size 7 382 | snprintf(sensor->node_names.remote_port, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 383 | sizeof(sensor->node_names.remote_port), | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 384 | SWNODE_GRAPH_PORT_NAME_FMT, sensor->link); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Hans Verkuil Acked-by: Arnd Bergmann --- include/media/ipu-bridge.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/media/ipu-bridge.h b/include/media/ipu-bridge.h index bdc654a455216..783bda6d5cc3f 100644 --- a/include/media/ipu-bridge.h +++ b/include/media/ipu-bridge.h @@ -108,7 +108,7 @@ struct ipu_node_names { char ivsc_sensor_port[7]; char ivsc_ipu_port[7]; char endpoint[11]; - char remote_port[7]; + char remote_port[9]; char vcm[16]; }; -- GitLab From 7c051b680048e4d79c5c0457ca370c0c09f69709 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:20:50 +0200 Subject: [PATCH 0371/1451] media: cx18: increase in_workq_name size Fixes this compiler warning: drivers/media/pci/cx18/cx18-driver.c: In function 'cx18_init_struct1': drivers/media/pci/cx18/cx18-driver.c:688:65: warning: '%s' directive output may be truncated writing up to 35 bytes into a region of size 11 [-Wformat-truncation=] 688 | snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in", | ^~ In function 'cx18_create_in_workq', inlined from 'cx18_init_struct1' at drivers/media/pci/cx18/cx18-driver.c:724:8: drivers/media/pci/cx18/cx18-driver.c:688:9: note: 'snprintf' output between 4 and 39 bytes into a destination of size 11 688 | snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in", | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 689 | cx->v4l2_dev.name); | ~~~~~~~~~~~~~~~~~~ Signed-off-by: Hans Verkuil Acked-by: Arnd Bergmann --- drivers/media/pci/cx18/cx18-driver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/cx18/cx18-driver.h b/drivers/media/pci/cx18/cx18-driver.h index 887d2aa364470..af05bde758165 100644 --- a/drivers/media/pci/cx18/cx18-driver.h +++ b/drivers/media/pci/cx18/cx18-driver.h @@ -631,7 +631,7 @@ struct cx18 { u32 hw2_irq_mask; struct workqueue_struct *in_work_queue; - char in_workq_name[11]; /* "cx18-NN-in" */ + char in_workq_name[39]; /* "cx18-NN-in" */ struct cx18_in_work_order in_work_order[CX18_MAX_IN_WORK_ORDERS]; char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */ -- GitLab From b05aba9fffd21bdf8168c7db8c2cd40e9d347f13 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:20:51 +0200 Subject: [PATCH 0372/1451] media: rc: ati_remote: increase mouse_name buffer size Fixes this compiler warning: drivers/media/rc/ati_remote.c: In function 'ati_remote_probe': drivers/media/rc/ati_remote.c:876:21: warning: ' mouse' directive output may be truncated writing 6 bytes into a region of size between 1 and 80 [-Wformat-truncation=] 876 | "%s mouse", ati_remote->rc_name); | ^~~~~~ drivers/media/rc/ati_remote.c:875:9: note: 'snprintf' output between 7 and 86 bytes into a destination of size 80 875 | snprintf(ati_remote->mouse_name, sizeof(ati_remote->mouse_name), | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 876 | "%s mouse", ati_remote->rc_name); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Hans Verkuil Reviewed-by: Sean Young Acked-by: Arnd Bergmann --- drivers/media/rc/ati_remote.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index fff4dd48eacad..d7721e60776ed 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -251,7 +251,7 @@ struct ati_remote { char rc_name[NAME_BUFSIZE]; char rc_phys[NAME_BUFSIZE]; - char mouse_name[NAME_BUFSIZE]; + char mouse_name[NAME_BUFSIZE + 6]; char mouse_phys[NAME_BUFSIZE]; wait_queue_head_t wait; -- GitLab From 7ba5e7b78b068e212c85926723990482ee7b1962 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:20:52 +0200 Subject: [PATCH 0373/1451] media: cec.h: increase input_phys buffer Fixes this compiler warning: drivers/media/cec/core/cec-core.c: In function 'cec_allocate_adapter': drivers/media/cec/core/cec-core.c:317:21: warning: '/input0' directive output may be truncated writing 7 bytes into a region of size between 1 and 32 [-Wformat-truncation=] 317 | "%s/input0", adap->name); | ^~~~~~~ drivers/media/cec/core/cec-core.c:316:9: note: 'snprintf' output between 8 and 39 bytes into a destination of size 32 316 | snprintf(adap->input_phys, sizeof(adap->input_phys), | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 317 | "%s/input0", adap->name); | ~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Hans Verkuil --- include/media/cec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/media/cec.h b/include/media/cec.h index 9c007f83569aa..53e4b2eb2b260 100644 --- a/include/media/cec.h +++ b/include/media/cec.h @@ -275,7 +275,7 @@ struct cec_adapter { u32 sequence; - char input_phys[32]; + char input_phys[40]; }; static inline void *cec_get_drvdata(const struct cec_adapter *adap) -- GitLab From acec3a11c32ca656aba682f4117e754501fa0746 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:20:53 +0200 Subject: [PATCH 0374/1451] media: renesas-ceu: keep input name simple Just show the Camera index as input name in VIDIOC_ENUM_INPUT, no need to show the subdev name as well as that is meaningless for users anyway. This fixes this compiler warning: drivers/media/platform/renesas/renesas-ceu.c: In function 'ceu_enum_input': drivers/media/platform/renesas/renesas-ceu.c:1195:59: warning: '%s' directive output may be truncated writing up to 47 bytes into a region of size between 14 and 23 [-Wformat-truncation=] 1195 | snprintf(inp->name, sizeof(inp->name), "Camera%u: %s", | ^~ drivers/media/platform/renesas/renesas-ceu.c:1195:9: note: 'snprintf' output between 10 and 66 bytes into a destination of size 32 1195 | snprintf(inp->name, sizeof(inp->name), "Camera%u: %s", | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1196 | inp->index, ceusd->v4l2_sd->name); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Hans Verkuil Reviewed-by: Jacopo Mondi --- drivers/media/platform/renesas/renesas-ceu.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/media/platform/renesas/renesas-ceu.c b/drivers/media/platform/renesas/renesas-ceu.c index ec631c6e2a571..2562b30acfb9b 100644 --- a/drivers/media/platform/renesas/renesas-ceu.c +++ b/drivers/media/platform/renesas/renesas-ceu.c @@ -1183,17 +1183,13 @@ static int ceu_enum_input(struct file *file, void *priv, struct v4l2_input *inp) { struct ceu_device *ceudev = video_drvdata(file); - struct ceu_subdev *ceusd; if (inp->index >= ceudev->num_sd) return -EINVAL; - ceusd = ceudev->subdevs[inp->index]; - inp->type = V4L2_INPUT_TYPE_CAMERA; inp->std = 0; - snprintf(inp->name, sizeof(inp->name), "Camera%u: %s", - inp->index, ceusd->v4l2_sd->name); + snprintf(inp->name, sizeof(inp->name), "Camera %u", inp->index); return 0; } -- GitLab From 3e80a88911a350438b60581daf11a115e020631d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:20:54 +0200 Subject: [PATCH 0375/1451] media: zoran: increase name size Fixes this compiler warning: drivers/media/pci/zoran/zoran_card.c: In function 'zoran_probe': drivers/media/pci/zoran/zoran_card.c:1316:62: warning: '%u' directive output may be truncated writing between 1 and 5 bytes into a region of size between 0 and 31 [-Wformat-truncation=] 1316 | snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "%s[%u]", | ^~ drivers/media/pci/zoran/zoran_card.c:1316:58: note: directive argument in the range [0, 65535] 1316 | snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "%s[%u]", | ^~~~~~~~ drivers/media/pci/zoran/zoran_card.c:1316:9: note: 'snprintf' output between 4 and 39 bytes into a destination of size 32 1316 | snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "%s[%u]", | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1317 | zr->card.name, zr->id); | ~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Hans Verkuil --- drivers/media/pci/zoran/zoran.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/zoran/zoran.h b/drivers/media/pci/zoran/zoran.h index 56340553b2823..1cd990468d3de 100644 --- a/drivers/media/pci/zoran/zoran.h +++ b/drivers/media/pci/zoran/zoran.h @@ -219,7 +219,7 @@ struct zoran { const struct tvnorm *timing; unsigned short id; /* number of this device */ - char name[32]; /* name of this device */ + char name[40]; /* name of this device */ struct pci_dev *pci_dev; /* PCI device */ unsigned char revision; /* revision of zr36057 */ unsigned char __iomem *zr36057_mem;/* pointer to mapped IO memory */ -- GitLab From 9cc0f40cac6ae5bc8529caa5e9d477678336450c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:20:55 +0200 Subject: [PATCH 0376/1451] media: v4l2-dev.h: increase struct video_device name size Increase the size of the name field to prevent a lot of string truncate compiler warnings. Signed-off-by: Hans Verkuil --- include/media/v4l2-dev.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index e0a13505f88da..d82dfdbf6e583 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -284,7 +284,7 @@ struct video_device { struct v4l2_prio_state *prio; /* device info */ - char name[32]; + char name[64]; enum vfl_devnode_type vfl_type; enum vfl_devnode_direction vfl_dir; int minor; -- GitLab From d9d432af1415b358d76b110c9e37e4f07d2e1c7b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:20:56 +0200 Subject: [PATCH 0377/1451] media: v4l2-subdev.h: increase struct v4l2_subdev name size This resolves a lot of the string truncate compiler warnings. Signed-off-by: Hans Verkuil --- drivers/staging/media/omap4iss/iss_csi2.c | 2 +- include/media/v4l2-subdev.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/omap4iss/iss_csi2.c b/drivers/staging/media/omap4iss/iss_csi2.c index 04ce0e7eb5578..d2844414de4f7 100644 --- a/drivers/staging/media/omap4iss/iss_csi2.c +++ b/drivers/staging/media/omap4iss/iss_csi2.c @@ -1260,7 +1260,7 @@ static int csi2_init_entities(struct iss_csi2_device *csi2, const char *subname) struct media_pad *pads = csi2->pads; struct media_entity *me = &sd->entity; int ret; - char name[V4L2_SUBDEV_NAME_SIZE]; + char name[32]; v4l2_subdev_init(sd, &csi2_ops); sd->internal_ops = &csi2_internal_ops; diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 5f59ff0796b71..5711354056b97 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -951,7 +951,7 @@ struct v4l2_subdev_internal_ops { void (*release)(struct v4l2_subdev *sd); }; -#define V4L2_SUBDEV_NAME_SIZE 32 +#define V4L2_SUBDEV_NAME_SIZE 52 /* Set this flag if this subdev is a i2c device. */ #define V4L2_SUBDEV_FL_IS_I2C (1U << 0) -- GitLab From 8cdd708f11655d5f28fca1ab2fa0dbe5424f274c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:20:57 +0200 Subject: [PATCH 0378/1451] media: use sizeof() instead of V4L2_SUBDEV_NAME_SIZE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't rely on a define, let the compiler use the actual field size. Remove all uses of the V4L2_SUBDEV_NAME_SIZE define and also drop the define itself. Signed-off-by: Hans Verkuil Reviewed-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Reviewed-by: Maxime Ripard Reviewed-by: Luca Ceresoli Tested-by: Luca Ceresoli --- drivers/media/i2c/msp3400-driver.c | 2 +- drivers/media/platform/cadence/cdns-csi2rx.c | 4 ++-- drivers/media/platform/cadence/cdns-csi2tx.c | 4 ++-- drivers/media/platform/renesas/rcar-isp.c | 2 +- drivers/media/platform/renesas/rcar-vin/rcar-csi2.c | 2 +- drivers/media/platform/ti/omap3isp/ispstat.c | 2 +- drivers/staging/media/tegra-video/csi.c | 4 ++-- drivers/staging/media/tegra-video/vip.c | 2 +- include/media/v4l2-subdev.h | 4 +--- 9 files changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c index bec76801487ab..0ed8561edfee6 100644 --- a/drivers/media/i2c/msp3400-driver.c +++ b/drivers/media/i2c/msp3400-driver.c @@ -561,7 +561,7 @@ static int msp_log_status(struct v4l2_subdev *sd) struct msp_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); const char *p; - char prefix[V4L2_SUBDEV_NAME_SIZE + 20]; + char prefix[sizeof(sd->name) + 20]; if (state->opmode == OPMODE_AUTOSELECT) msp_detect_stereo(client); diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index 0d879d71d8185..b9d9058e2ce3f 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -516,8 +516,8 @@ static int csi2rx_probe(struct platform_device *pdev) csi2rx->subdev.dev = &pdev->dev; v4l2_subdev_init(&csi2rx->subdev, &csi2rx_subdev_ops); v4l2_set_subdevdata(&csi2rx->subdev, &pdev->dev); - snprintf(csi2rx->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s.%s", - KBUILD_MODNAME, dev_name(&pdev->dev)); + snprintf(csi2rx->subdev.name, sizeof(csi2rx->subdev.name), + "%s.%s", KBUILD_MODNAME, dev_name(&pdev->dev)); /* Create our media pads */ csi2rx->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; diff --git a/drivers/media/platform/cadence/cdns-csi2tx.c b/drivers/media/platform/cadence/cdns-csi2tx.c index cbbb775201126..c115742f347ff 100644 --- a/drivers/media/platform/cadence/cdns-csi2tx.c +++ b/drivers/media/platform/cadence/cdns-csi2tx.c @@ -592,8 +592,8 @@ static int csi2tx_probe(struct platform_device *pdev) csi2tx->subdev.owner = THIS_MODULE; csi2tx->subdev.dev = &pdev->dev; csi2tx->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - snprintf(csi2tx->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s.%s", - KBUILD_MODNAME, dev_name(&pdev->dev)); + snprintf(csi2tx->subdev.name, sizeof(csi2tx->subdev.name), + "%s.%s", KBUILD_MODNAME, dev_name(&pdev->dev)); ret = csi2tx_check_lanes(csi2tx); if (ret) diff --git a/drivers/media/platform/renesas/rcar-isp.c b/drivers/media/platform/renesas/rcar-isp.c index 7360cf3863f2c..19a005d837330 100644 --- a/drivers/media/platform/renesas/rcar-isp.c +++ b/drivers/media/platform/renesas/rcar-isp.c @@ -467,7 +467,7 @@ static int risp_probe(struct platform_device *pdev) isp->subdev.dev = &pdev->dev; v4l2_subdev_init(&isp->subdev, &rcar_isp_subdev_ops); v4l2_set_subdevdata(&isp->subdev, &pdev->dev); - snprintf(isp->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s %s", + snprintf(isp->subdev.name, sizeof(isp->subdev.name), "%s %s", KBUILD_MODNAME, dev_name(&pdev->dev)); isp->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c index f6326df0b09be..66fe553a00e75 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c @@ -1889,7 +1889,7 @@ static int rcsi2_probe(struct platform_device *pdev) priv->subdev.dev = &pdev->dev; v4l2_subdev_init(&priv->subdev, &rcar_csi2_subdev_ops); v4l2_set_subdevdata(&priv->subdev, &pdev->dev); - snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s %s", + snprintf(priv->subdev.name, sizeof(priv->subdev.name), "%s %s", KBUILD_MODNAME, dev_name(&pdev->dev)); priv->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; diff --git a/drivers/media/platform/ti/omap3isp/ispstat.c b/drivers/media/platform/ti/omap3isp/ispstat.c index 68cf68dbcace2..359a846205b0f 100644 --- a/drivers/media/platform/ti/omap3isp/ispstat.c +++ b/drivers/media/platform/ti/omap3isp/ispstat.c @@ -1039,7 +1039,7 @@ static int isp_stat_init_entities(struct ispstat *stat, const char *name, struct media_entity *me = &subdev->entity; v4l2_subdev_init(subdev, sd_ops); - snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name); + snprintf(subdev->name, sizeof(subdev->name), "OMAP3 ISP %s", name); subdev->grp_id = BIT(16); /* group ID for isp subdevs */ subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; v4l2_set_subdevdata(subdev, stat); diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c index e79657920dc8a..9aa72863c213e 100644 --- a/drivers/staging/media/tegra-video/csi.c +++ b/drivers/staging/media/tegra-video/csi.c @@ -607,10 +607,10 @@ static int tegra_csi_channel_init(struct tegra_csi_channel *chan) v4l2_subdev_init(subdev, &tegra_csi_ops); subdev->dev = csi->dev; if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG)) - snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "%s-%d", "tpg", + snprintf(subdev->name, sizeof(subdev->name), "%s-%d", "tpg", chan->csi_port_nums[0]); else - snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "%s", + snprintf(subdev->name, sizeof(subdev->name), "%s", kbasename(chan->of_node->full_name)); v4l2_set_subdevdata(subdev, chan); diff --git a/drivers/staging/media/tegra-video/vip.c b/drivers/staging/media/tegra-video/vip.c index 191ecd19a6a7c..e95cc7bb190e1 100644 --- a/drivers/staging/media/tegra-video/vip.c +++ b/drivers/staging/media/tegra-video/vip.c @@ -163,7 +163,7 @@ static int tegra_vip_channel_init(struct tegra_vip *vip) subdev = &vip->chan.subdev; v4l2_subdev_init(subdev, &tegra_vip_ops); subdev->dev = vip->dev; - snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "%s", + snprintf(subdev->name, sizeof(subdev->name), "%s", kbasename(vip->chan.of_node->full_name)); v4l2_set_subdevdata(subdev, &vip->chan); diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 5711354056b97..c1f90c1223a74 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -951,8 +951,6 @@ struct v4l2_subdev_internal_ops { void (*release)(struct v4l2_subdev *sd); }; -#define V4L2_SUBDEV_NAME_SIZE 52 - /* Set this flag if this subdev is a i2c device. */ #define V4L2_SUBDEV_FL_IS_I2C (1U << 0) /* Set this flag if this subdev is a spi device. */ @@ -1062,7 +1060,7 @@ struct v4l2_subdev { const struct v4l2_subdev_ops *ops; const struct v4l2_subdev_internal_ops *internal_ops; struct v4l2_ctrl_handler *ctrl_handler; - char name[V4L2_SUBDEV_NAME_SIZE]; + char name[52]; u32 grp_id; void *dev_priv; void *host_priv; -- GitLab From 06016a67c61675642c71358c2afe6ce99b5d1468 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:20:58 +0200 Subject: [PATCH 0379/1451] media: v4l2-device.h: drop V4L2_DEVICE_NAME_SIZE Don't use defines for the size of a name field, everyone should just use sizeof(). In this case it was never used, but it is bad practice, so just drop it. Signed-off-by: Hans Verkuil --- include/media/v4l2-device.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h index 8a8977a33ec10..f6f111fae33c0 100644 --- a/include/media/v4l2-device.h +++ b/include/media/v4l2-device.h @@ -13,8 +13,6 @@ #include #include -#define V4L2_DEVICE_NAME_SIZE (20 + 16) - struct v4l2_ctrl_handler; /** @@ -49,7 +47,7 @@ struct v4l2_device { struct media_device *mdev; struct list_head subdevs; spinlock_t lock; - char name[V4L2_DEVICE_NAME_SIZE]; + char name[36]; void (*notify)(struct v4l2_subdev *sd, unsigned int notification, void *arg); struct v4l2_ctrl_handler *ctrl_handler; -- GitLab From 10939357c4cc178d4a8628a728cb33f70b3d4edd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:20:59 +0200 Subject: [PATCH 0380/1451] media: vivid: use VIVID_MODULE_NAME to fill bus_info Fixes this compiler warning: drivers/media/test-drivers/vivid/vivid-core.c: In function 'vidioc_querycap': drivers/media/test-drivers/vivid/vivid-core.c:243:35: warning: '%s' directive output may be truncated writing up to 35 bytes into a region of size 23 [-Wformat-truncation=] 243 | "platform:%s", dev->v4l2_dev.name); | ^~ drivers/media/test-drivers/vivid/vivid-core.c:242:9: note: 'snprintf' output between 10 and 45 bytes into a destination of size 32 242 | snprintf(cap->bus_info, sizeof(cap->bus_info), | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 243 | "platform:%s", dev->v4l2_dev.name); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Hans Verkuil --- drivers/media/test-drivers/vivid/vivid-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c index e95bdccfc18e9..394c9f81ea727 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.c +++ b/drivers/media/test-drivers/vivid/vivid-core.c @@ -240,7 +240,7 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, "vivid", sizeof(cap->driver)); strscpy(cap->card, "vivid", sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", dev->v4l2_dev.name); + "platform:%s-%03d", VIVID_MODULE_NAME, dev->inst); cap->capabilities = dev->vid_cap_caps | dev->vid_out_caps | dev->vbi_cap_caps | dev->vbi_out_caps | -- GitLab From 4ebdec2aeed3362c5920468f7dbf11883f72ac33 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:21:00 +0200 Subject: [PATCH 0381/1451] media: microchip: don't set bus_info Let the V4L2 core fill this in. Fixes these compiler warnings: drivers/media/platform/microchip/microchip-isc-base.c: In function 'isc_querycap': drivers/media/platform/microchip/microchip-isc-base.c:486:28: warning: '%s' directive output may be truncated writing up to 35 bytes into a region of size 23 [-Wformat-truncation=] 486 | "platform:%s", isc->v4l2_dev.name); | ^~ drivers/media/platform/microchip/microchip-isc-base.c:485:9: note: 'snprintf' output between 10 and 45 bytes into a destination of size 32 485 | snprintf(cap->bus_info, sizeof(cap->bus_info), | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 486 | "platform:%s", isc->v4l2_dev.name); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/media/platform/microchip/microchip-isc-base.c: In function 'isc_mc_init': drivers/media/platform/microchip/microchip-isc-base.c:1996:76: warning: '%s' directive output may be truncated writing up to 35 bytes into a region of size 23 [-Wformat-truncation=] 1996 | snprintf(isc->mdev.bus_info, sizeof(isc->mdev.bus_info), "platform:%s", | ^~ drivers/media/platform/microchip/microchip-isc-base.c:1996:9: note: 'snprintf' output between 10 and 45 bytes into a destination of size 32 1996 | snprintf(isc->mdev.bus_info, sizeof(isc->mdev.bus_info), "platform:%s", | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1997 | isc->v4l2_dev.name); | ~~~~~~~~~~~~~~~~~~~ Signed-off-by: Hans Verkuil Acked-by: Nicolas Ferre --- drivers/media/platform/microchip/microchip-isc-base.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c index 8dbf7bc1e863b..1f85288444970 100644 --- a/drivers/media/platform/microchip/microchip-isc-base.c +++ b/drivers/media/platform/microchip/microchip-isc-base.c @@ -478,12 +478,8 @@ static const struct vb2_ops isc_vb2_ops = { static int isc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct isc_device *isc = video_drvdata(file); - strscpy(cap->driver, "microchip-isc", sizeof(cap->driver)); strscpy(cap->card, "Microchip Image Sensor Controller", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", isc->v4l2_dev.name); return 0; } @@ -1993,8 +1989,6 @@ int isc_mc_init(struct isc_device *isc, u32 ver) strscpy(isc->mdev.driver_name, KBUILD_MODNAME, sizeof(isc->mdev.driver_name)); strscpy(isc->mdev.model, match->compatible, sizeof(isc->mdev.model)); - snprintf(isc->mdev.bus_info, sizeof(isc->mdev.bus_info), "platform:%s", - isc->v4l2_dev.name); isc->mdev.hw_revision = ver; media_device_init(&isc->mdev); -- GitLab From 37272d21cec670e27f0a2e3117bb5116b2d6ca2d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:21:01 +0200 Subject: [PATCH 0382/1451] media: rcar_drif: use explicit name for bus_info Fixes this compiler warning: drivers/media/platform/renesas/rcar_drif.c: In function 'rcar_drif_querycap': drivers/media/platform/renesas/rcar_drif.c:874:66: warning: '%s' directive output may be truncated writing up to 63 bytes into a region of size 23 [-Wformat-truncation=] 874 | snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", | ^~ drivers/media/platform/renesas/rcar_drif.c:874:9: note: 'snprintf' output between 10 and 73 bytes into a destination of size 32 874 | snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 875 | sdr->vdev->name); | ~~~~~~~~~~~~~~~~ Signed-off-by: Hans Verkuil --- drivers/media/platform/renesas/rcar_drif.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/platform/renesas/rcar_drif.c b/drivers/media/platform/renesas/rcar_drif.c index 163a4ba61c173..292c5bf9e50c3 100644 --- a/drivers/media/platform/renesas/rcar_drif.c +++ b/drivers/media/platform/renesas/rcar_drif.c @@ -871,8 +871,7 @@ static int rcar_drif_querycap(struct file *file, void *fh, strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strscpy(cap->card, sdr->vdev->name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - sdr->vdev->name); + strscpy(cap->bus_info, "platform:R-Car DRIF", sizeof(cap->bus_info)); return 0; } -- GitLab From bd6ef410676e9a2729ebea2b5cd43689f521dfd3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:21:02 +0200 Subject: [PATCH 0383/1451] media: am437x: don't fill in bus_info Let the V4L2 core fill this in. This fixes this warning: drivers/media/platform/ti/am437x/am437x-vpfe.c: In function 'vpfe_querycap': drivers/media/platform/ti/am437x/am437x-vpfe.c:1279:35: warning: '%s' directive output may be truncated writing up to 35 bytes into a region of size 23 [-Wformat-truncation=] 1279 | "platform:%s", vpfe->v4l2_dev.name); | ^~ drivers/media/platform/ti/am437x/am437x-vpfe.c:1278:9: note: 'snprintf' output between 10 and 45 bytes into a destination of size 32 1278 | snprintf(cap->bus_info, sizeof(cap->bus_info), | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1279 | "platform:%s", vpfe->v4l2_dev.name); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Hans Verkuil Reviewed-by: Lad Prabhakar --- drivers/media/platform/ti/am437x/am437x-vpfe.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/platform/ti/am437x/am437x-vpfe.c b/drivers/media/platform/ti/am437x/am437x-vpfe.c index 63092013d476e..5fa2ea9025d96 100644 --- a/drivers/media/platform/ti/am437x/am437x-vpfe.c +++ b/drivers/media/platform/ti/am437x/am437x-vpfe.c @@ -1271,12 +1271,8 @@ static inline void vpfe_attach_irq(struct vpfe_device *vpfe) static int vpfe_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct vpfe_device *vpfe = video_drvdata(file); - strscpy(cap->driver, VPFE_MODULE_NAME, sizeof(cap->driver)); strscpy(cap->card, "TI AM437x VPFE", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", vpfe->v4l2_dev.name); return 0; } -- GitLab From 127299a41cf96caa9ef02c6f0bb9af1d93cfc55a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:21:03 +0200 Subject: [PATCH 0384/1451] media: atmel: drop bus_info Let the V4L2 core fill this in. Fixes this warning: drivers/staging/media/deprecated/atmel/atmel-isc-base.c: In function 'isc_querycap': drivers/staging/media/deprecated/atmel/atmel-isc-base.c:496:28: warning: '%s' directive output may be truncated writing up to 35 bytes into a region of size 23 [-Wformat-truncation=] 496 | "platform:%s", isc->v4l2_dev.name); | ^~ drivers/staging/media/deprecated/atmel/atmel-isc-base.c:495:9: note: 'snprintf' output between 10 and 45 bytes into a destination of size 32 495 | snprintf(cap->bus_info, sizeof(cap->bus_info), | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 496 | "platform:%s", isc->v4l2_dev.name); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Hans Verkuil Acked-by: Nicolas Ferre --- drivers/staging/media/deprecated/atmel/atmel-isc-base.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/staging/media/deprecated/atmel/atmel-isc-base.c b/drivers/staging/media/deprecated/atmel/atmel-isc-base.c index f5d963904201f..8e26663cecb63 100644 --- a/drivers/staging/media/deprecated/atmel/atmel-isc-base.c +++ b/drivers/staging/media/deprecated/atmel/atmel-isc-base.c @@ -488,12 +488,8 @@ static const struct vb2_ops isc_vb2_ops = { static int isc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct isc_device *isc = video_drvdata(file); - strscpy(cap->driver, "microchip-isc", sizeof(cap->driver)); strscpy(cap->card, "Atmel Image Sensor Controller", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", isc->v4l2_dev.name); return 0; } -- GitLab From 8b7f3cf4eb9a95940eaabad3226caeaa0d9aa59d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:21:04 +0200 Subject: [PATCH 0385/1451] media: radio-isa: use dev_name to fill in bus_info This fixes this warning: drivers/media/radio/radio-isa.c: In function 'radio_isa_querycap': drivers/media/radio/radio-isa.c:39:57: warning: '%s' directive output may be truncated writing up to 35 bytes into a region of size 28 [-Wformat-truncation=] 39 | snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", isa->v4l2_dev.name); | ^~ drivers/media/radio/radio-isa.c:39:9: note: 'snprintf' output between 5 and 40 bytes into a destination of size 32 39 | snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", isa->v4l2_dev.name); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Hans Verkuil --- drivers/media/radio/radio-isa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c index c591c0851fa28..ad49151f5ff09 100644 --- a/drivers/media/radio/radio-isa.c +++ b/drivers/media/radio/radio-isa.c @@ -36,7 +36,7 @@ static int radio_isa_querycap(struct file *file, void *priv, strscpy(v->driver, isa->drv->driver.driver.name, sizeof(v->driver)); strscpy(v->card, isa->drv->card, sizeof(v->card)); - snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", isa->v4l2_dev.name); + snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", dev_name(isa->v4l2_dev.dev)); return 0; } -- GitLab From b74093bfbcada7c45ea7425118cd8ee57314162d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:21:05 +0200 Subject: [PATCH 0386/1451] media: radio-miropcm20: set bus_info to explicit name Fill in bus_info with fixed name. This fixes this compiler warning: drivers/media/radio/radio-miropcm20.c: In function 'vidioc_querycap': drivers/media/radio/radio-miropcm20.c:206:57: warning: '%s' directive output may be truncated writing up to 35 bytes into a region of size 28 [-Wformat-truncation=] 206 | snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", dev->v4l2_dev.name); | ^~ drivers/media/radio/radio-miropcm20.c:206:9: note: 'snprintf' output between 5 and 40 bytes into a destination of size 32 206 | snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", dev->v4l2_dev.name); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Hans Verkuil --- drivers/media/radio/radio-miropcm20.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c index 99788834c6461..08be77b8f3b71 100644 --- a/drivers/media/radio/radio-miropcm20.c +++ b/drivers/media/radio/radio-miropcm20.c @@ -199,11 +199,9 @@ static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq) static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) { - struct pcm20 *dev = video_drvdata(file); - strscpy(v->driver, "Miro PCM20", sizeof(v->driver)); strscpy(v->card, "Miro PCM20", sizeof(v->card)); - snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", dev->v4l2_dev.name); + strscpy(v->bus_info, "ISA:radio-miropcm20", sizeof(v->bus_info)); return 0; } -- GitLab From b66215e7b7802caf6aceba0928a437d40e15d3f1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:21:06 +0200 Subject: [PATCH 0387/1451] media: verisilicon: replace snprintf with strscpy+strlcat Fixes this warning: drivers/media/platform/verisilicon/hantro_drv.c: In function 'hantro_add_func': drivers/media/platform/verisilicon/hantro_drv.c:902:49: warning: '%s' directive output may be truncated writing up to 127 bytes into a region of size 64 [-Wformat-truncation=] 902 | snprintf(vfd->name, sizeof(vfd->name), "%s-%s", match->compatible, | ^~ drivers/media/platform/verisilicon/hantro_drv.c:902:9: note: 'snprintf' output between 5 and 132 bytes into a destination of size 64 902 | snprintf(vfd->name, sizeof(vfd->name), "%s-%s", match->compatible, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 903 | funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER ? "enc" : "dec"); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/media/platform/verisilicon/hantro_drv.c:902:49: warning: '%s' directive output may be truncated writing up to 127 bytes into a region of size 64 [-Wformat-truncation=] 902 | snprintf(vfd->name, sizeof(vfd->name), "%s-%s", match->compatible, | ^~ drivers/media/platform/verisilicon/hantro_drv.c:902:9: note: 'snprintf' output between 5 and 132 bytes into a destination of size 64 902 | snprintf(vfd->name, sizeof(vfd->name), "%s-%s", match->compatible, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 903 | funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER ? "enc" : "dec"); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Hans Verkuil --- drivers/media/platform/verisilicon/hantro_drv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index 50ec24c753e9e..a9fa05ac56a9b 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -899,8 +899,9 @@ static int hantro_add_func(struct hantro_dev *vpu, unsigned int funcid) vfd->vfl_dir = VFL_DIR_M2M; vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; vfd->ioctl_ops = &hantro_ioctl_ops; - snprintf(vfd->name, sizeof(vfd->name), "%s-%s", match->compatible, - funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER ? "enc" : "dec"); + strscpy(vfd->name, match->compatible, sizeof(vfd->name)); + strlcat(vfd->name, funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER ? + "-enc" : "-dec", sizeof(vfd->name)); if (funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER) { vpu->encoder = func; -- GitLab From fd6627cb82d5e991dedbd972a219311eabe89884 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 23 Sep 2023 17:21:07 +0200 Subject: [PATCH 0388/1451] media: radio-si476x: don't fill in bus_info Let the V4L2 core fill in bus_info. This fixes this warning: drivers/media/radio/radio-si476x.c: In function 'si476x_radio_querycap': drivers/media/radio/radio-si476x.c:333:28: warning: '%s' directive output may be truncated writing up to 35 bytes into a region of size 23 [-Wformat-truncation=] 333 | "platform:%s", radio->v4l2dev.name); | ^~ drivers/media/radio/radio-si476x.c:332:9: note: 'snprintf' output between 10 and 45 bytes into a destination of size 32 332 | snprintf(capability->bus_info, sizeof(capability->bus_info), | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 333 | "platform:%s", radio->v4l2dev.name); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Hans Verkuil --- drivers/media/radio/radio-si476x.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c index 6061506159f1b..b2c5809a8bc71 100644 --- a/drivers/media/radio/radio-si476x.c +++ b/drivers/media/radio/radio-si476x.c @@ -328,9 +328,7 @@ static int si476x_radio_querycap(struct file *file, void *priv, strscpy(capability->driver, radio->v4l2dev.name, sizeof(capability->driver)); - strscpy(capability->card, DRIVER_CARD, sizeof(capability->card)); - snprintf(capability->bus_info, sizeof(capability->bus_info), - "platform:%s", radio->v4l2dev.name); + strscpy(capability->card, DRIVER_CARD, sizeof(capability->card)); return 0; } -- GitLab From e96c6b8f212a510c9b22362de519f6e1d7920de5 Mon Sep 17 00:00:00 2001 From: Song Shuai Date: Sat, 24 Jun 2023 11:26:07 +0800 Subject: [PATCH 0389/1451] memblock: report failures when memblock_can_resize is not set The callers of memblock_reserve() do not check the return value presuming that memblock_reserve() always succeeds, but there are cases where it may fail. Having numerous memblock reservations at early boot where memblock_can_resize is unset may exhaust the INIT_MEMBLOCK_REGIONS sized memblock.reserved regions array and an attempt to double this array via memblock_double_array() will fail and will return -1 to the caller. When this happens the system crashes anyway, but it's hard to identify the reason for the crash. Add a panic message to memblock_double_array() to aid debugging of the cases when too many regions are reserved before memblock can resize memblock.reserved array. Link: https://lore.kernel.org/linux-kernel/20230614131746.3670303-1-songshuaishuai@tinylab.org/ Signed-off-by: Song Shuai Link: https://lore.kernel.org/r/20230624032607.921173-1-songshuaishuai@tinylab.org Signed-off-by: Mike Rapoport (IBM) --- mm/memblock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/memblock.c b/mm/memblock.c index 913b2520a9a00..0863222af4a48 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -424,7 +424,7 @@ static int __init_memblock memblock_double_array(struct memblock_type *type, * of memory that aren't suitable for allocation */ if (!memblock_can_resize) - return -1; + panic("memblock: cannot resize %s array\n", type->name); /* Calculate new doubled size */ old_size = type->max * sizeof(struct memblock_region); -- GitLab From 6013727fc33d9361fb01cb4d072134d3d37a1c1a Mon Sep 17 00:00:00 2001 From: Tanmay Shah Date: Mon, 25 Sep 2023 10:26:48 -0700 Subject: [PATCH 0390/1451] remoteproc: zynqmp: Change tcm address translation method Introduce device address in hardcode TCM table. Device address is used for address translation. Also, previous method(hack) to mask few bits from address to achieve address translation is removed Signed-off-by: Tanmay Shah Link: https://lore.kernel.org/r/20230925172648.2339048-1-tanmay.shah@amd.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/xlnx_r5_remoteproc.c | 58 +++++++++---------------- 1 file changed, 20 insertions(+), 38 deletions(-) diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c index efd758c2f4ed1..4395edea9a646 100644 --- a/drivers/remoteproc/xlnx_r5_remoteproc.c +++ b/drivers/remoteproc/xlnx_r5_remoteproc.c @@ -39,12 +39,14 @@ enum zynqmp_r5_cluster_mode { * struct mem_bank_data - Memory Bank description * * @addr: Start address of memory bank + * @da: device address * @size: Size of Memory bank * @pm_domain_id: Power-domains id of memory bank for firmware to turn on/off * @bank_name: name of the bank for remoteproc framework */ struct mem_bank_data { phys_addr_t addr; + u32 da; size_t size; u32 pm_domain_id; char *bank_name; @@ -76,18 +78,18 @@ struct mbox_info { * accepted for system-dt specifications and upstreamed in linux kernel */ static const struct mem_bank_data zynqmp_tcm_banks_split[] = { - {0xffe00000UL, 0x10000UL, PD_R5_0_ATCM, "atcm0"}, /* TCM 64KB each */ - {0xffe20000UL, 0x10000UL, PD_R5_0_BTCM, "btcm0"}, - {0xffe90000UL, 0x10000UL, PD_R5_1_ATCM, "atcm1"}, - {0xffeb0000UL, 0x10000UL, PD_R5_1_BTCM, "btcm1"}, + {0xffe00000UL, 0x0, 0x10000UL, PD_R5_0_ATCM, "atcm0"}, /* TCM 64KB each */ + {0xffe20000UL, 0x20000, 0x10000UL, PD_R5_0_BTCM, "btcm0"}, + {0xffe90000UL, 0x0, 0x10000UL, PD_R5_1_ATCM, "atcm1"}, + {0xffeb0000UL, 0x20000, 0x10000UL, PD_R5_1_BTCM, "btcm1"}, }; /* In lockstep mode cluster combines each 64KB TCM and makes 128KB TCM */ static const struct mem_bank_data zynqmp_tcm_banks_lockstep[] = { - {0xffe00000UL, 0x20000UL, PD_R5_0_ATCM, "atcm0"}, /* TCM 128KB each */ - {0xffe20000UL, 0x20000UL, PD_R5_0_BTCM, "btcm0"}, - {0, 0, PD_R5_1_ATCM, ""}, - {0, 0, PD_R5_1_BTCM, ""}, + {0xffe00000UL, 0x0, 0x20000UL, PD_R5_0_ATCM, "atcm0"}, /* TCM 128KB each */ + {0xffe20000UL, 0x20000, 0x20000UL, PD_R5_0_BTCM, "btcm0"}, + {0, 0, 0, PD_R5_1_ATCM, ""}, + {0, 0, 0, PD_R5_1_BTCM, ""}, }; /** @@ -534,30 +536,6 @@ static int tcm_mem_map(struct rproc *rproc, /* clear TCMs */ memset_io(va, 0, mem->len); - /* - * The R5s expect their TCM banks to be at address 0x0 and 0x2000, - * while on the Linux side they are at 0xffexxxxx. - * - * Zero out the high 12 bits of the address. This will give - * expected values for TCM Banks 0A and 0B (0x0 and 0x20000). - */ - mem->da &= 0x000fffff; - - /* - * TCM Banks 1A and 1B still have to be translated. - * - * Below handle these two banks' absolute addresses (0xffe90000 and - * 0xffeb0000) and convert to the expected relative addresses - * (0x0 and 0x20000). - */ - if (mem->da == 0x90000 || mem->da == 0xB0000) - mem->da -= 0x90000; - - /* if translated TCM bank address is not valid report error */ - if (mem->da != 0x0 && mem->da != 0x20000) { - dev_err(&rproc->dev, "invalid TCM address: %x\n", mem->da); - return -EINVAL; - } return 0; } @@ -579,6 +557,7 @@ static int add_tcm_carveout_split_mode(struct rproc *rproc) u32 pm_domain_id; size_t bank_size; char *bank_name; + u32 da; r5_core = rproc->priv; dev = r5_core->dev; @@ -591,6 +570,7 @@ static int add_tcm_carveout_split_mode(struct rproc *rproc) */ for (i = 0; i < num_banks; i++) { bank_addr = r5_core->tcm_banks[i]->addr; + da = r5_core->tcm_banks[i]->da; bank_name = r5_core->tcm_banks[i]->bank_name; bank_size = r5_core->tcm_banks[i]->size; pm_domain_id = r5_core->tcm_banks[i]->pm_domain_id; @@ -603,11 +583,11 @@ static int add_tcm_carveout_split_mode(struct rproc *rproc) goto release_tcm_split; } - dev_dbg(dev, "TCM carveout split mode %s addr=%llx, size=0x%lx", - bank_name, bank_addr, bank_size); + dev_dbg(dev, "TCM carveout split mode %s addr=%llx, da=0x%x, size=0x%lx", + bank_name, bank_addr, da, bank_size); rproc_mem = rproc_mem_entry_init(dev, NULL, bank_addr, - bank_size, bank_addr, + bank_size, da, tcm_mem_map, tcm_mem_unmap, bank_name); if (!rproc_mem) { @@ -648,6 +628,7 @@ static int add_tcm_carveout_lockstep_mode(struct rproc *rproc) struct device *dev; u32 pm_domain_id; char *bank_name; + u32 da; r5_core = rproc->priv; dev = r5_core->dev; @@ -679,11 +660,12 @@ static int add_tcm_carveout_lockstep_mode(struct rproc *rproc) continue; bank_addr = r5_core->tcm_banks[i]->addr; + da = r5_core->tcm_banks[i]->da; bank_name = r5_core->tcm_banks[i]->bank_name; /* Register TCM address range, TCM map and unmap functions */ rproc_mem = rproc_mem_entry_init(dev, NULL, bank_addr, - bank_size, bank_addr, + bank_size, da, tcm_mem_map, tcm_mem_unmap, bank_name); if (!rproc_mem) { @@ -695,8 +677,8 @@ static int add_tcm_carveout_lockstep_mode(struct rproc *rproc) /* If registration is success, add carveouts */ rproc_add_carveout(rproc, rproc_mem); - dev_dbg(dev, "TCM add carveout lockstep mode %s addr=0x%llx, size=0x%lx", - bank_name, bank_addr, bank_size); + dev_dbg(dev, "TCM carveout lockstep mode %s addr=0x%llx, da=0x%x, size=0x%lx", + bank_name, bank_addr, da, bank_size); } return 0; -- GitLab From 96609688ab8a8ec25c4eeced53e88e26cff4fb06 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Sat, 30 Sep 2023 09:05:07 -0700 Subject: [PATCH 0391/1451] Input: synaptics-rmi4 - replace deprecated strncpy `strncpy` is deprecated for use on NUL-terminated destination strings [1] Let's use memcpy() as the bounds have already been checked and this decays into a simple byte copy from one buffer to another removing any ambiguity that strncpy has. Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20230921-strncpy-drivers-input-rmi4-rmi_f34-c-v1-1-4aef2e84b8d2@google.com Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_f34.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/rmi4/rmi_f34.c b/drivers/input/rmi4/rmi_f34.c index 0d9a5756e3f59..3b3ac71e53dc5 100644 --- a/drivers/input/rmi4/rmi_f34.c +++ b/drivers/input/rmi4/rmi_f34.c @@ -471,7 +471,7 @@ static ssize_t rmi_driver_update_fw_store(struct device *dev, if (buf[count - 1] == '\0' || buf[count - 1] == '\n') copy_count -= 1; - strncpy(fw_name, buf, copy_count); + memcpy(fw_name, buf, copy_count); fw_name[copy_count] = '\0'; ret = request_firmware(&fw, fw_name, dev); -- GitLab From 8927e688e9e0ae625af6a917bace8cc9cac55677 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sat, 30 Sep 2023 09:17:43 -0700 Subject: [PATCH 0392/1451] Input: evdev - annotate struct evdev_client with __counted_by Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct evdev_client. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20230922175027.work.563-kees@kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 95f90699d2b17..51e0c49546001 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -50,7 +50,7 @@ struct evdev_client { bool revoked; unsigned long *evmasks[EV_CNT]; unsigned int bufsize; - struct input_event buffer[]; + struct input_event buffer[] __counted_by(bufsize); }; static size_t evdev_get_mask_cnt(unsigned int type) -- GitLab From 21d7ec79ef5b1c23495dd88e5679c1a1d6dd17ae Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sat, 30 Sep 2023 09:19:13 -0700 Subject: [PATCH 0393/1451] Input: leds - annotate struct input_leds with __counted_by Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct input_leds. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20230922175031.work.467-kees@kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/input-leds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/input-leds.c b/drivers/input/input-leds.c index 0b11990ade465..0e935914bc3aa 100644 --- a/drivers/input/input-leds.c +++ b/drivers/input/input-leds.c @@ -44,7 +44,7 @@ struct input_led { struct input_leds { struct input_handle handle; unsigned int num_leds; - struct input_led leds[]; + struct input_led leds[] __counted_by(num_leds); }; static enum led_brightness input_leds_brightness_get(struct led_classdev *cdev) -- GitLab From 348cbf987ed328682af7d74ce98d9f0e6857f42f Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sat, 30 Sep 2023 09:20:20 -0700 Subject: [PATCH 0394/1451] Input: mt - annotate struct input_mt with __counted_by Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct input_mt. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20230922175036.work.762-kees@kernel.org Signed-off-by: Dmitry Torokhov --- include/linux/input/mt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/input/mt.h b/include/linux/input/mt.h index 3b8580bd33c14..2cf89a538b18b 100644 --- a/include/linux/input/mt.h +++ b/include/linux/input/mt.h @@ -47,7 +47,7 @@ struct input_mt { unsigned int flags; unsigned int frame; int *red; - struct input_mt_slot slots[]; + struct input_mt_slot slots[] __counted_by(num_slots); }; static inline void input_mt_set_value(struct input_mt_slot *slot, -- GitLab From 68ede283a1d8fe0813b218aeb498faf3b0fc0a7b Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Sat, 30 Sep 2023 09:32:31 -0700 Subject: [PATCH 0395/1451] Input: axp20x-pek - avoid needless newline removal This code is doing more work than it needs to. Before handing off `val_str` to `kstrtouint()` we are eagerly removing any trailing newline which requires copying `buf`, validating it's length and checking/replacing any potential newlines. kstrtouint() handles this implicitly: kstrtouint -> kstrotoull -> (documentation) | /** | * kstrtoull - convert a string to an unsigned long long | * @s: The start of the string. The string must be null-terminated, and may also | * include a single newline before its terminating null. The first character | ... Let's remove the redundant functionality and let kstrtouint handle it. Suggested-by: Kees Cook Signed-off-by: Justin Stitt Reviewed-by: Chen-Yu Tsai Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20230925-strncpy-drivers-input-misc-axp20x-pek-c-v2-1-ff7abe8498d6@google.com Signed-off-by: Dmitry Torokhov --- drivers/input/misc/axp20x-pek.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c index 4581606a28d63..24f9e9d893de3 100644 --- a/drivers/input/misc/axp20x-pek.c +++ b/drivers/input/misc/axp20x-pek.c @@ -133,20 +133,11 @@ static ssize_t axp20x_store_attr(struct device *dev, size_t count) { struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev); - char val_str[20]; - size_t len; int ret, i; unsigned int val, idx = 0; unsigned int best_err = UINT_MAX; - val_str[sizeof(val_str) - 1] = '\0'; - strncpy(val_str, buf, sizeof(val_str) - 1); - len = strlen(val_str); - - if (len && val_str[len - 1] == '\n') - val_str[len - 1] = '\0'; - - ret = kstrtouint(val_str, 10, &val); + ret = kstrtouint(buf, 10, &val); if (ret) return ret; -- GitLab From fa4c4507099f781ca89a748c480af9cf97629726 Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Thu, 28 Sep 2023 16:31:35 +0200 Subject: [PATCH 0396/1451] iommu: Allow .iotlb_sync_map to fail and handle s390's -ENOMEM return On s390 when using a paging hypervisor, .iotlb_sync_map is used to sync mappings by letting the hypervisor inspect the synced IOVA range and updating a shadow table. This however means that .iotlb_sync_map can fail as the hypervisor may run out of resources while doing the sync. This can be due to the hypervisor being unable to pin guest pages, due to a limit on mapped addresses such as vfio_iommu_type1.dma_entry_limit or lack of other resources. Either way such a failure to sync a mapping should result in a DMA_MAPPING_ERROR. Now especially when running with batched IOTLB flushes for unmap it may be that some IOVAs have already been invalidated but not yet synced via .iotlb_sync_map. Thus if the hypervisor indicates running out of resources, first do a global flush allowing the hypervisor to free resources associated with these mappings as well a retry creating the new mappings and only if that also fails report this error to callers. Reviewed-by: Lu Baolu Reviewed-by: Matthew Rosato Acked-by: Jernej Skrabec # sun50i Signed-off-by: Niklas Schnelle Link: https://lore.kernel.org/r/20230928-dma_iommu-v13-1-9e5fc4dacc36@linux.ibm.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/iommu.c | 5 +++-- drivers/iommu/apple-dart.c | 5 +++-- drivers/iommu/intel/iommu.c | 5 +++-- drivers/iommu/iommu.c | 20 ++++++++++++++++---- drivers/iommu/msm_iommu.c | 5 +++-- drivers/iommu/mtk_iommu.c | 5 +++-- drivers/iommu/s390-iommu.c | 29 +++++++++++++++++++++++------ drivers/iommu/sprd-iommu.c | 5 +++-- drivers/iommu/sun50i-iommu.c | 6 ++++-- include/linux/iommu.h | 4 ++-- 10 files changed, 63 insertions(+), 26 deletions(-) diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 95bd7c25ba6f3..74229b1607a17 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -2233,14 +2233,15 @@ static int amd_iommu_attach_device(struct iommu_domain *dom, return ret; } -static void amd_iommu_iotlb_sync_map(struct iommu_domain *dom, - unsigned long iova, size_t size) +static int amd_iommu_iotlb_sync_map(struct iommu_domain *dom, + unsigned long iova, size_t size) { struct protection_domain *domain = to_pdomain(dom); struct io_pgtable_ops *ops = &domain->iop.iop.ops; if (ops->map_pages) domain_flush_np_cache(domain, iova, size); + return 0; } static int amd_iommu_map_pages(struct iommu_domain *dom, unsigned long iova, diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index 2082081402d32..22880a42ccaa6 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -506,10 +506,11 @@ static void apple_dart_iotlb_sync(struct iommu_domain *domain, apple_dart_domain_flush_tlb(to_dart_domain(domain)); } -static void apple_dart_iotlb_sync_map(struct iommu_domain *domain, - unsigned long iova, size_t size) +static int apple_dart_iotlb_sync_map(struct iommu_domain *domain, + unsigned long iova, size_t size) { apple_dart_domain_flush_tlb(to_dart_domain(domain)); + return 0; } static phys_addr_t apple_dart_iova_to_phys(struct iommu_domain *domain, diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 5db283c17e0dc..4779375135025 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -4678,8 +4678,8 @@ static bool risky_device(struct pci_dev *pdev) return false; } -static void intel_iommu_iotlb_sync_map(struct iommu_domain *domain, - unsigned long iova, size_t size) +static int intel_iommu_iotlb_sync_map(struct iommu_domain *domain, + unsigned long iova, size_t size) { struct dmar_domain *dmar_domain = to_dmar_domain(domain); unsigned long pages = aligned_nrpages(iova, size); @@ -4689,6 +4689,7 @@ static void intel_iommu_iotlb_sync_map(struct iommu_domain *domain, xa_for_each(&dmar_domain->iommu_array, i, info) __mapping_notify_one(info->iommu, dmar_domain, pfn, pages); + return 0; } static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 1ecac2b5c54f4..1cc9d139c860c 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -2585,8 +2585,17 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova, return -EINVAL; ret = __iommu_map(domain, iova, paddr, size, prot, gfp); - if (ret == 0 && ops->iotlb_sync_map) - ops->iotlb_sync_map(domain, iova, size); + if (ret == 0 && ops->iotlb_sync_map) { + ret = ops->iotlb_sync_map(domain, iova, size); + if (ret) + goto out_err; + } + + return ret; + +out_err: + /* undo mappings already done */ + iommu_unmap(domain, iova, size); return ret; } @@ -2714,8 +2723,11 @@ ssize_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova, sg = sg_next(sg); } - if (ops->iotlb_sync_map) - ops->iotlb_sync_map(domain, iova, mapped); + if (ops->iotlb_sync_map) { + ret = ops->iotlb_sync_map(domain, iova, mapped); + if (ret) + goto out_err; + } return mapped; out_err: diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c index a163cee0b7242..f86af9815d6f9 100644 --- a/drivers/iommu/msm_iommu.c +++ b/drivers/iommu/msm_iommu.c @@ -498,12 +498,13 @@ static int msm_iommu_map(struct iommu_domain *domain, unsigned long iova, return ret; } -static void msm_iommu_sync_map(struct iommu_domain *domain, unsigned long iova, - size_t size) +static int msm_iommu_sync_map(struct iommu_domain *domain, unsigned long iova, + size_t size) { struct msm_priv *priv = to_msm_priv(domain); __flush_iotlb_range(iova, size, SZ_4K, false, priv); + return 0; } static size_t msm_iommu_unmap(struct iommu_domain *domain, unsigned long iova, diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index 19ef50221c93d..2d8e95246781b 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -837,12 +837,13 @@ static void mtk_iommu_iotlb_sync(struct iommu_domain *domain, mtk_iommu_tlb_flush_range_sync(gather->start, length, dom->bank); } -static void mtk_iommu_sync_map(struct iommu_domain *domain, unsigned long iova, - size_t size) +static int mtk_iommu_sync_map(struct iommu_domain *domain, unsigned long iova, + size_t size) { struct mtk_iommu_domain *dom = to_mtk_domain(domain); mtk_iommu_tlb_flush_range_sync(iova, size, dom->bank); + return 0; } static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain, diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c index 5695ad71d60e2..560d0957f9bef 100644 --- a/drivers/iommu/s390-iommu.c +++ b/drivers/iommu/s390-iommu.c @@ -219,6 +219,12 @@ static void s390_iommu_release_device(struct device *dev) __s390_iommu_detach_device(zdev); } +static int zpci_refresh_all(struct zpci_dev *zdev) +{ + return zpci_refresh_trans((u64)zdev->fh << 32, zdev->start_dma, + zdev->end_dma - zdev->start_dma + 1); +} + static void s390_iommu_flush_iotlb_all(struct iommu_domain *domain) { struct s390_domain *s390_domain = to_s390_domain(domain); @@ -226,8 +232,7 @@ static void s390_iommu_flush_iotlb_all(struct iommu_domain *domain) rcu_read_lock(); list_for_each_entry_rcu(zdev, &s390_domain->devices, iommu_list) { - zpci_refresh_trans((u64)zdev->fh << 32, zdev->start_dma, - zdev->end_dma - zdev->start_dma + 1); + zpci_refresh_all(zdev); } rcu_read_unlock(); } @@ -251,20 +256,32 @@ static void s390_iommu_iotlb_sync(struct iommu_domain *domain, rcu_read_unlock(); } -static void s390_iommu_iotlb_sync_map(struct iommu_domain *domain, - unsigned long iova, size_t size) +static int s390_iommu_iotlb_sync_map(struct iommu_domain *domain, + unsigned long iova, size_t size) { struct s390_domain *s390_domain = to_s390_domain(domain); struct zpci_dev *zdev; + int ret = 0; rcu_read_lock(); list_for_each_entry_rcu(zdev, &s390_domain->devices, iommu_list) { if (!zdev->tlb_refresh) continue; - zpci_refresh_trans((u64)zdev->fh << 32, - iova, size); + ret = zpci_refresh_trans((u64)zdev->fh << 32, + iova, size); + /* + * let the hypervisor discover invalidated entries + * allowing it to free IOVAs and unpin pages + */ + if (ret == -ENOMEM) { + ret = zpci_refresh_all(zdev); + if (ret) + break; + } } rcu_read_unlock(); + + return ret; } static int s390_iommu_validate_trans(struct s390_domain *s390_domain, diff --git a/drivers/iommu/sprd-iommu.c b/drivers/iommu/sprd-iommu.c index 9c33ea6903f6c..2eb9fb46703b3 100644 --- a/drivers/iommu/sprd-iommu.c +++ b/drivers/iommu/sprd-iommu.c @@ -341,8 +341,8 @@ static size_t sprd_iommu_unmap(struct iommu_domain *domain, unsigned long iova, return size; } -static void sprd_iommu_sync_map(struct iommu_domain *domain, - unsigned long iova, size_t size) +static int sprd_iommu_sync_map(struct iommu_domain *domain, + unsigned long iova, size_t size) { struct sprd_iommu_domain *dom = to_sprd_domain(domain); unsigned int reg; @@ -354,6 +354,7 @@ static void sprd_iommu_sync_map(struct iommu_domain *domain, /* clear IOMMU TLB buffer after page table updated */ sprd_iommu_write(dom->sdev, reg, 0xffffffff); + return 0; } static void sprd_iommu_sync(struct iommu_domain *domain, diff --git a/drivers/iommu/sun50i-iommu.c b/drivers/iommu/sun50i-iommu.c index 3c834854eda13..41484a5a399bb 100644 --- a/drivers/iommu/sun50i-iommu.c +++ b/drivers/iommu/sun50i-iommu.c @@ -401,8 +401,8 @@ static void sun50i_iommu_flush_iotlb_all(struct iommu_domain *domain) spin_unlock_irqrestore(&iommu->iommu_lock, flags); } -static void sun50i_iommu_iotlb_sync_map(struct iommu_domain *domain, - unsigned long iova, size_t size) +static int sun50i_iommu_iotlb_sync_map(struct iommu_domain *domain, + unsigned long iova, size_t size) { struct sun50i_iommu_domain *sun50i_domain = to_sun50i_domain(domain); struct sun50i_iommu *iommu = sun50i_domain->iommu; @@ -411,6 +411,8 @@ static void sun50i_iommu_iotlb_sync_map(struct iommu_domain *domain, spin_lock_irqsave(&iommu->iommu_lock, flags); sun50i_iommu_zap_range(iommu, iova, size); spin_unlock_irqrestore(&iommu->iommu_lock, flags); + + return 0; } static void sun50i_iommu_iotlb_sync(struct iommu_domain *domain, diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 64bd20142cbed..1eb6387527810 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -350,8 +350,8 @@ struct iommu_domain_ops { struct iommu_iotlb_gather *iotlb_gather); void (*flush_iotlb_all)(struct iommu_domain *domain); - void (*iotlb_sync_map)(struct iommu_domain *domain, unsigned long iova, - size_t size); + int (*iotlb_sync_map)(struct iommu_domain *domain, unsigned long iova, + size_t size); void (*iotlb_sync)(struct iommu_domain *domain, struct iommu_iotlb_gather *iotlb_gather); -- GitLab From b6f888709a155b4e748aded93afc9fa43aaa28dd Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Thu, 28 Sep 2023 16:31:36 +0200 Subject: [PATCH 0397/1451] s390/pci: prepare is_passed_through() for dma-iommu With the IOMMU always controlled through the IOMMU driver testing for zdev->s390_domain is not a valid indication of the device being passed-through. Instead test if zdev->kzdev is set. Reviewed-by: Pierre Morel Reviewed-by: Matthew Rosato Signed-off-by: Niklas Schnelle Link: https://lore.kernel.org/r/20230928-dma_iommu-v13-2-9e5fc4dacc36@linux.ibm.com Signed-off-by: Joerg Roedel --- arch/s390/pci/pci_event.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c index b9324ca2eb940..4ef5a6a1d6187 100644 --- a/arch/s390/pci/pci_event.c +++ b/arch/s390/pci/pci_event.c @@ -59,9 +59,16 @@ static inline bool ers_result_indicates_abort(pci_ers_result_t ers_res) } } -static bool is_passed_through(struct zpci_dev *zdev) +static bool is_passed_through(struct pci_dev *pdev) { - return zdev->s390_domain; + struct zpci_dev *zdev = to_zpci(pdev); + bool ret; + + mutex_lock(&zdev->kzdev_lock); + ret = !!zdev->kzdev; + mutex_unlock(&zdev->kzdev_lock); + + return ret; } static bool is_driver_supported(struct pci_driver *driver) @@ -176,7 +183,7 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev) } pdev->error_state = pci_channel_io_frozen; - if (is_passed_through(to_zpci(pdev))) { + if (is_passed_through(pdev)) { pr_info("%s: Cannot be recovered in the host because it is a pass-through device\n", pci_name(pdev)); goto out_unlock; @@ -239,7 +246,7 @@ static void zpci_event_io_failure(struct pci_dev *pdev, pci_channel_state_t es) * we will inject the error event and let the guest recover the device * itself. */ - if (is_passed_through(to_zpci(pdev))) + if (is_passed_through(pdev)) goto out; driver = to_pci_driver(pdev->dev.driver); if (driver && driver->err_handler && driver->err_handler->error_detected) -- GitLab From c76c067e488ccd55734c3e750799caf2c5956db6 Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Thu, 28 Sep 2023 16:31:37 +0200 Subject: [PATCH 0398/1451] s390/pci: Use dma-iommu layer While s390 already has a standard IOMMU driver and previous changes have added I/O TLB flushing operations this driver is currently only used for user-space PCI access such as vfio-pci. For the DMA API s390 instead utilizes its own implementation in arch/s390/pci/pci_dma.c which drives the same hardware and shares some code but requires a complex and fragile hand over between DMA API and IOMMU API use of a device and despite code sharing still leads to significant duplication and maintenance effort. Let's utilize the common code DMAP API implementation from drivers/iommu/dma-iommu.c instead allowing us to get rid of arch/s390/pci/pci_dma.c. Reviewed-by: Matthew Rosato Signed-off-by: Niklas Schnelle Link: https://lore.kernel.org/r/20230928-dma_iommu-v13-3-9e5fc4dacc36@linux.ibm.com Signed-off-by: Joerg Roedel --- .../admin-guide/kernel-parameters.txt | 9 +- arch/s390/include/asm/pci.h | 7 - arch/s390/include/asm/pci_clp.h | 3 + arch/s390/include/asm/pci_dma.h | 121 +-- arch/s390/pci/Makefile | 2 +- arch/s390/pci/pci.c | 22 +- arch/s390/pci/pci_bus.c | 5 - arch/s390/pci/pci_debug.c | 12 +- arch/s390/pci/pci_dma.c | 735 ------------------ arch/s390/pci/pci_event.c | 2 - arch/s390/pci/pci_sysfs.c | 19 +- drivers/iommu/Kconfig | 4 +- drivers/iommu/s390-iommu.c | 400 +++++++++- 13 files changed, 402 insertions(+), 939 deletions(-) delete mode 100644 arch/s390/pci/pci_dma.c diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 0a1731a0f0ef3..14f56c448edc4 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2220,7 +2220,7 @@ forcing Dual Address Cycle for PCI cards supporting greater than 32-bit addressing. - iommu.strict= [ARM64, X86] Configure TLB invalidation behaviour + iommu.strict= [ARM64, X86, S390] Configure TLB invalidation behaviour Format: { "0" | "1" } 0 - Lazy mode. Request that DMA unmap operations use deferred @@ -5611,9 +5611,10 @@ s390_iommu= [HW,S390] Set s390 IOTLB flushing mode strict - With strict flushing every unmap operation will result in - an IOTLB flush. Default is lazy flushing before reuse, - which is faster. + With strict flushing every unmap operation will result + in an IOTLB flush. Default is lazy flushing before + reuse, which is faster. Deprecated, equivalent to + iommu.strict=1. s390_iommu_aperture= [KNL,S390] Specifies the size of the per device DMA address space diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index b248694e00247..3f74f1cf37dfd 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h @@ -159,13 +159,6 @@ struct zpci_dev { unsigned long *dma_table; int tlb_refresh; - spinlock_t iommu_bitmap_lock; - unsigned long *iommu_bitmap; - unsigned long *lazy_bitmap; - unsigned long iommu_size; - unsigned long iommu_pages; - unsigned int next_bit; - struct iommu_device iommu_dev; /* IOMMU core handle */ char res_name[16]; diff --git a/arch/s390/include/asm/pci_clp.h b/arch/s390/include/asm/pci_clp.h index d6189ed14f848..f0c677ddd2706 100644 --- a/arch/s390/include/asm/pci_clp.h +++ b/arch/s390/include/asm/pci_clp.h @@ -50,6 +50,9 @@ struct clp_fh_list_entry { #define CLP_UTIL_STR_LEN 64 #define CLP_PFIP_NR_SEGMENTS 4 +/* PCI function type numbers */ +#define PCI_FUNC_TYPE_ISM 0x5 /* ISM device */ + extern bool zpci_unique_uid; struct clp_rsp_slpc_pci { diff --git a/arch/s390/include/asm/pci_dma.h b/arch/s390/include/asm/pci_dma.h index 7119c04c51c5c..42d7cc4262ca4 100644 --- a/arch/s390/include/asm/pci_dma.h +++ b/arch/s390/include/asm/pci_dma.h @@ -82,117 +82,16 @@ enum zpci_ioat_dtype { #define ZPCI_TABLE_VALID_MASK 0x20 #define ZPCI_TABLE_PROT_MASK 0x200 -static inline unsigned int calc_rtx(dma_addr_t ptr) -{ - return ((unsigned long) ptr >> ZPCI_RT_SHIFT) & ZPCI_INDEX_MASK; -} - -static inline unsigned int calc_sx(dma_addr_t ptr) -{ - return ((unsigned long) ptr >> ZPCI_ST_SHIFT) & ZPCI_INDEX_MASK; -} - -static inline unsigned int calc_px(dma_addr_t ptr) -{ - return ((unsigned long) ptr >> PAGE_SHIFT) & ZPCI_PT_MASK; -} - -static inline void set_pt_pfaa(unsigned long *entry, phys_addr_t pfaa) -{ - *entry &= ZPCI_PTE_FLAG_MASK; - *entry |= (pfaa & ZPCI_PTE_ADDR_MASK); -} - -static inline void set_rt_sto(unsigned long *entry, phys_addr_t sto) -{ - *entry &= ZPCI_RTE_FLAG_MASK; - *entry |= (sto & ZPCI_RTE_ADDR_MASK); - *entry |= ZPCI_TABLE_TYPE_RTX; -} - -static inline void set_st_pto(unsigned long *entry, phys_addr_t pto) -{ - *entry &= ZPCI_STE_FLAG_MASK; - *entry |= (pto & ZPCI_STE_ADDR_MASK); - *entry |= ZPCI_TABLE_TYPE_SX; -} - -static inline void validate_rt_entry(unsigned long *entry) -{ - *entry &= ~ZPCI_TABLE_VALID_MASK; - *entry &= ~ZPCI_TABLE_OFFSET_MASK; - *entry |= ZPCI_TABLE_VALID; - *entry |= ZPCI_TABLE_LEN_RTX; -} - -static inline void validate_st_entry(unsigned long *entry) -{ - *entry &= ~ZPCI_TABLE_VALID_MASK; - *entry |= ZPCI_TABLE_VALID; -} - -static inline void invalidate_pt_entry(unsigned long *entry) -{ - WARN_ON_ONCE((*entry & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_INVALID); - *entry &= ~ZPCI_PTE_VALID_MASK; - *entry |= ZPCI_PTE_INVALID; -} - -static inline void validate_pt_entry(unsigned long *entry) -{ - WARN_ON_ONCE((*entry & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID); - *entry &= ~ZPCI_PTE_VALID_MASK; - *entry |= ZPCI_PTE_VALID; -} - -static inline void entry_set_protected(unsigned long *entry) -{ - *entry &= ~ZPCI_TABLE_PROT_MASK; - *entry |= ZPCI_TABLE_PROTECTED; -} - -static inline void entry_clr_protected(unsigned long *entry) -{ - *entry &= ~ZPCI_TABLE_PROT_MASK; - *entry |= ZPCI_TABLE_UNPROTECTED; -} - -static inline int reg_entry_isvalid(unsigned long entry) -{ - return (entry & ZPCI_TABLE_VALID_MASK) == ZPCI_TABLE_VALID; -} - -static inline int pt_entry_isvalid(unsigned long entry) -{ - return (entry & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID; -} - -static inline unsigned long *get_rt_sto(unsigned long entry) -{ - if ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_RTX) - return phys_to_virt(entry & ZPCI_RTE_ADDR_MASK); - else - return NULL; - -} - -static inline unsigned long *get_st_pto(unsigned long entry) -{ - if ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_SX) - return phys_to_virt(entry & ZPCI_STE_ADDR_MASK); - else - return NULL; -} - -/* Prototypes */ -void dma_free_seg_table(unsigned long); -unsigned long *dma_alloc_cpu_table(gfp_t gfp); -void dma_cleanup_tables(unsigned long *); -unsigned long *dma_walk_cpu_trans(unsigned long *rto, dma_addr_t dma_addr, - gfp_t gfp); -void dma_update_cpu_trans(unsigned long *entry, phys_addr_t page_addr, int flags); - -extern const struct dma_map_ops s390_pci_dma_ops; +struct zpci_iommu_ctrs { + atomic64_t mapped_pages; + atomic64_t unmapped_pages; + atomic64_t global_rpcits; + atomic64_t sync_map_rpcits; + atomic64_t sync_rpcits; +}; + +struct zpci_dev; +struct zpci_iommu_ctrs *zpci_get_iommu_ctrs(struct zpci_dev *zdev); #endif diff --git a/arch/s390/pci/Makefile b/arch/s390/pci/Makefile index 5ae31ca9dd441..0547a10406e72 100644 --- a/arch/s390/pci/Makefile +++ b/arch/s390/pci/Makefile @@ -3,7 +3,7 @@ # Makefile for the s390 PCI subsystem. # -obj-$(CONFIG_PCI) += pci.o pci_irq.o pci_dma.o pci_clp.o pci_sysfs.o \ +obj-$(CONFIG_PCI) += pci.o pci_irq.o pci_clp.o pci_sysfs.o \ pci_event.o pci_debug.o pci_insn.o pci_mmio.o \ pci_bus.o pci_kvm_hook.o obj-$(CONFIG_PCI_IOV) += pci_iov.o diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index d34d5813d0066..563cb72d9ed0f 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -124,7 +124,11 @@ int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas, WARN_ON_ONCE(iota & 0x3fff); fib.pba = base; - fib.pal = limit; + /* Work around off by one in ISM virt device */ + if (zdev->pft == PCI_FUNC_TYPE_ISM && limit > base) + fib.pal = limit + (1 << 12); + else + fib.pal = limit; fib.iota = iota | ZPCI_IOTA_RTTO_FLAG; fib.gd = zdev->gisa; cc = zpci_mod_fc(req, &fib, status); @@ -582,7 +586,6 @@ int pcibios_device_add(struct pci_dev *pdev) pdev->no_vf_scan = 1; pdev->dev.groups = zpci_attr_groups; - pdev->dev.dma_ops = &s390_pci_dma_ops; zpci_map_resources(pdev); for (i = 0; i < PCI_STD_NUM_BARS; i++) { @@ -756,8 +759,6 @@ int zpci_hot_reset_device(struct zpci_dev *zdev) if (zdev->dma_table) rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, virt_to_phys(zdev->dma_table), &status); - else - rc = zpci_dma_init_device(zdev); if (rc) { zpci_disable_device(zdev); return rc; @@ -865,11 +866,6 @@ int zpci_deconfigure_device(struct zpci_dev *zdev) if (zdev->zbus->bus) zpci_bus_remove_device(zdev, false); - if (zdev->dma_table) { - rc = zpci_dma_exit_device(zdev); - if (rc) - return rc; - } if (zdev_enabled(zdev)) { rc = zpci_disable_device(zdev); if (rc) @@ -918,8 +914,6 @@ void zpci_release_device(struct kref *kref) if (zdev->zbus->bus) zpci_bus_remove_device(zdev, false); - if (zdev->dma_table) - zpci_dma_exit_device(zdev); if (zdev_enabled(zdev)) zpci_disable_device(zdev); @@ -1109,10 +1103,6 @@ static int __init pci_base_init(void) if (rc) goto out_irq; - rc = zpci_dma_init(); - if (rc) - goto out_dma; - rc = clp_scan_pci_devices(); if (rc) goto out_find; @@ -1122,8 +1112,6 @@ static int __init pci_base_init(void) return 0; out_find: - zpci_dma_exit(); -out_dma: zpci_irq_exit(); out_irq: zpci_mem_exit(); diff --git a/arch/s390/pci/pci_bus.c b/arch/s390/pci/pci_bus.c index 32245b970a0cf..daa5d7450c7d3 100644 --- a/arch/s390/pci/pci_bus.c +++ b/arch/s390/pci/pci_bus.c @@ -47,11 +47,6 @@ static int zpci_bus_prepare_device(struct zpci_dev *zdev) rc = zpci_enable_device(zdev); if (rc) return rc; - rc = zpci_dma_init_device(zdev); - if (rc) { - zpci_disable_device(zdev); - return rc; - } } if (!zdev->has_resources) { diff --git a/arch/s390/pci/pci_debug.c b/arch/s390/pci/pci_debug.c index ca6bd98eec136..6dde2263c79d1 100644 --- a/arch/s390/pci/pci_debug.c +++ b/arch/s390/pci/pci_debug.c @@ -53,9 +53,11 @@ static char *pci_fmt3_names[] = { }; static char *pci_sw_names[] = { - "Allocated pages", "Mapped pages", "Unmapped pages", + "Global RPCITs", + "Sync Map RPCITs", + "Sync RPCITs", }; static void pci_fmb_show(struct seq_file *m, char *name[], int length, @@ -69,10 +71,14 @@ static void pci_fmb_show(struct seq_file *m, char *name[], int length, static void pci_sw_counter_show(struct seq_file *m) { - struct zpci_dev *zdev = m->private; - atomic64_t *counter = &zdev->allocated_pages; + struct zpci_iommu_ctrs *ctrs = zpci_get_iommu_ctrs(m->private); + atomic64_t *counter; int i; + if (!ctrs) + return; + + counter = &ctrs->mapped_pages; for (i = 0; i < ARRAY_SIZE(pci_sw_names); i++, counter++) seq_printf(m, "%26s:\t%llu\n", pci_sw_names[i], atomic64_read(counter)); diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c deleted file mode 100644 index 2d9b01d7ca4c5..0000000000000 --- a/arch/s390/pci/pci_dma.c +++ /dev/null @@ -1,735 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright IBM Corp. 2012 - * - * Author(s): - * Jan Glauber - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static struct kmem_cache *dma_region_table_cache; -static struct kmem_cache *dma_page_table_cache; -static int s390_iommu_strict; -static u64 s390_iommu_aperture; -static u32 s390_iommu_aperture_factor = 1; - -static int zpci_refresh_global(struct zpci_dev *zdev) -{ - return zpci_refresh_trans((u64) zdev->fh << 32, zdev->start_dma, - zdev->iommu_pages * PAGE_SIZE); -} - -unsigned long *dma_alloc_cpu_table(gfp_t gfp) -{ - unsigned long *table, *entry; - - table = kmem_cache_alloc(dma_region_table_cache, gfp); - if (!table) - return NULL; - - for (entry = table; entry < table + ZPCI_TABLE_ENTRIES; entry++) - *entry = ZPCI_TABLE_INVALID; - return table; -} - -static void dma_free_cpu_table(void *table) -{ - kmem_cache_free(dma_region_table_cache, table); -} - -static unsigned long *dma_alloc_page_table(gfp_t gfp) -{ - unsigned long *table, *entry; - - table = kmem_cache_alloc(dma_page_table_cache, gfp); - if (!table) - return NULL; - - for (entry = table; entry < table + ZPCI_PT_ENTRIES; entry++) - *entry = ZPCI_PTE_INVALID; - return table; -} - -static void dma_free_page_table(void *table) -{ - kmem_cache_free(dma_page_table_cache, table); -} - -static unsigned long *dma_get_seg_table_origin(unsigned long *rtep, gfp_t gfp) -{ - unsigned long old_rte, rte; - unsigned long *sto; - - rte = READ_ONCE(*rtep); - if (reg_entry_isvalid(rte)) { - sto = get_rt_sto(rte); - } else { - sto = dma_alloc_cpu_table(gfp); - if (!sto) - return NULL; - - set_rt_sto(&rte, virt_to_phys(sto)); - validate_rt_entry(&rte); - entry_clr_protected(&rte); - - old_rte = cmpxchg(rtep, ZPCI_TABLE_INVALID, rte); - if (old_rte != ZPCI_TABLE_INVALID) { - /* Somone else was faster, use theirs */ - dma_free_cpu_table(sto); - sto = get_rt_sto(old_rte); - } - } - return sto; -} - -static unsigned long *dma_get_page_table_origin(unsigned long *step, gfp_t gfp) -{ - unsigned long old_ste, ste; - unsigned long *pto; - - ste = READ_ONCE(*step); - if (reg_entry_isvalid(ste)) { - pto = get_st_pto(ste); - } else { - pto = dma_alloc_page_table(gfp); - if (!pto) - return NULL; - set_st_pto(&ste, virt_to_phys(pto)); - validate_st_entry(&ste); - entry_clr_protected(&ste); - - old_ste = cmpxchg(step, ZPCI_TABLE_INVALID, ste); - if (old_ste != ZPCI_TABLE_INVALID) { - /* Somone else was faster, use theirs */ - dma_free_page_table(pto); - pto = get_st_pto(old_ste); - } - } - return pto; -} - -unsigned long *dma_walk_cpu_trans(unsigned long *rto, dma_addr_t dma_addr, - gfp_t gfp) -{ - unsigned long *sto, *pto; - unsigned int rtx, sx, px; - - rtx = calc_rtx(dma_addr); - sto = dma_get_seg_table_origin(&rto[rtx], gfp); - if (!sto) - return NULL; - - sx = calc_sx(dma_addr); - pto = dma_get_page_table_origin(&sto[sx], gfp); - if (!pto) - return NULL; - - px = calc_px(dma_addr); - return &pto[px]; -} - -void dma_update_cpu_trans(unsigned long *ptep, phys_addr_t page_addr, int flags) -{ - unsigned long pte; - - pte = READ_ONCE(*ptep); - if (flags & ZPCI_PTE_INVALID) { - invalidate_pt_entry(&pte); - } else { - set_pt_pfaa(&pte, page_addr); - validate_pt_entry(&pte); - } - - if (flags & ZPCI_TABLE_PROTECTED) - entry_set_protected(&pte); - else - entry_clr_protected(&pte); - - xchg(ptep, pte); -} - -static int __dma_update_trans(struct zpci_dev *zdev, phys_addr_t pa, - dma_addr_t dma_addr, size_t size, int flags) -{ - unsigned int nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; - phys_addr_t page_addr = (pa & PAGE_MASK); - unsigned long *entry; - int i, rc = 0; - - if (!nr_pages) - return -EINVAL; - - if (!zdev->dma_table) - return -EINVAL; - - for (i = 0; i < nr_pages; i++) { - entry = dma_walk_cpu_trans(zdev->dma_table, dma_addr, - GFP_ATOMIC); - if (!entry) { - rc = -ENOMEM; - goto undo_cpu_trans; - } - dma_update_cpu_trans(entry, page_addr, flags); - page_addr += PAGE_SIZE; - dma_addr += PAGE_SIZE; - } - -undo_cpu_trans: - if (rc && ((flags & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID)) { - flags = ZPCI_PTE_INVALID; - while (i-- > 0) { - page_addr -= PAGE_SIZE; - dma_addr -= PAGE_SIZE; - entry = dma_walk_cpu_trans(zdev->dma_table, dma_addr, - GFP_ATOMIC); - if (!entry) - break; - dma_update_cpu_trans(entry, page_addr, flags); - } - } - return rc; -} - -static int __dma_purge_tlb(struct zpci_dev *zdev, dma_addr_t dma_addr, - size_t size, int flags) -{ - unsigned long irqflags; - int ret; - - /* - * With zdev->tlb_refresh == 0, rpcit is not required to establish new - * translations when previously invalid translation-table entries are - * validated. With lazy unmap, rpcit is skipped for previously valid - * entries, but a global rpcit is then required before any address can - * be re-used, i.e. after each iommu bitmap wrap-around. - */ - if ((flags & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID) { - if (!zdev->tlb_refresh) - return 0; - } else { - if (!s390_iommu_strict) - return 0; - } - - ret = zpci_refresh_trans((u64) zdev->fh << 32, dma_addr, - PAGE_ALIGN(size)); - if (ret == -ENOMEM && !s390_iommu_strict) { - /* enable the hypervisor to free some resources */ - if (zpci_refresh_global(zdev)) - goto out; - - spin_lock_irqsave(&zdev->iommu_bitmap_lock, irqflags); - bitmap_andnot(zdev->iommu_bitmap, zdev->iommu_bitmap, - zdev->lazy_bitmap, zdev->iommu_pages); - bitmap_zero(zdev->lazy_bitmap, zdev->iommu_pages); - spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, irqflags); - ret = 0; - } -out: - return ret; -} - -static int dma_update_trans(struct zpci_dev *zdev, phys_addr_t pa, - dma_addr_t dma_addr, size_t size, int flags) -{ - int rc; - - rc = __dma_update_trans(zdev, pa, dma_addr, size, flags); - if (rc) - return rc; - - rc = __dma_purge_tlb(zdev, dma_addr, size, flags); - if (rc && ((flags & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID)) - __dma_update_trans(zdev, pa, dma_addr, size, ZPCI_PTE_INVALID); - - return rc; -} - -void dma_free_seg_table(unsigned long entry) -{ - unsigned long *sto = get_rt_sto(entry); - int sx; - - for (sx = 0; sx < ZPCI_TABLE_ENTRIES; sx++) - if (reg_entry_isvalid(sto[sx])) - dma_free_page_table(get_st_pto(sto[sx])); - - dma_free_cpu_table(sto); -} - -void dma_cleanup_tables(unsigned long *table) -{ - int rtx; - - if (!table) - return; - - for (rtx = 0; rtx < ZPCI_TABLE_ENTRIES; rtx++) - if (reg_entry_isvalid(table[rtx])) - dma_free_seg_table(table[rtx]); - - dma_free_cpu_table(table); -} - -static unsigned long __dma_alloc_iommu(struct device *dev, - unsigned long start, int size) -{ - struct zpci_dev *zdev = to_zpci(to_pci_dev(dev)); - - return iommu_area_alloc(zdev->iommu_bitmap, zdev->iommu_pages, - start, size, zdev->start_dma >> PAGE_SHIFT, - dma_get_seg_boundary_nr_pages(dev, PAGE_SHIFT), - 0); -} - -static dma_addr_t dma_alloc_address(struct device *dev, int size) -{ - struct zpci_dev *zdev = to_zpci(to_pci_dev(dev)); - unsigned long offset, flags; - - spin_lock_irqsave(&zdev->iommu_bitmap_lock, flags); - offset = __dma_alloc_iommu(dev, zdev->next_bit, size); - if (offset == -1) { - if (!s390_iommu_strict) { - /* global flush before DMA addresses are reused */ - if (zpci_refresh_global(zdev)) - goto out_error; - - bitmap_andnot(zdev->iommu_bitmap, zdev->iommu_bitmap, - zdev->lazy_bitmap, zdev->iommu_pages); - bitmap_zero(zdev->lazy_bitmap, zdev->iommu_pages); - } - /* wrap-around */ - offset = __dma_alloc_iommu(dev, 0, size); - if (offset == -1) - goto out_error; - } - zdev->next_bit = offset + size; - spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, flags); - - return zdev->start_dma + offset * PAGE_SIZE; - -out_error: - spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, flags); - return DMA_MAPPING_ERROR; -} - -static void dma_free_address(struct device *dev, dma_addr_t dma_addr, int size) -{ - struct zpci_dev *zdev = to_zpci(to_pci_dev(dev)); - unsigned long flags, offset; - - offset = (dma_addr - zdev->start_dma) >> PAGE_SHIFT; - - spin_lock_irqsave(&zdev->iommu_bitmap_lock, flags); - if (!zdev->iommu_bitmap) - goto out; - - if (s390_iommu_strict) - bitmap_clear(zdev->iommu_bitmap, offset, size); - else - bitmap_set(zdev->lazy_bitmap, offset, size); - -out: - spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, flags); -} - -static inline void zpci_err_dma(unsigned long rc, unsigned long addr) -{ - struct { - unsigned long rc; - unsigned long addr; - } __packed data = {rc, addr}; - - zpci_err_hex(&data, sizeof(data)); -} - -static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction direction, - unsigned long attrs) -{ - struct zpci_dev *zdev = to_zpci(to_pci_dev(dev)); - unsigned long pa = page_to_phys(page) + offset; - int flags = ZPCI_PTE_VALID; - unsigned long nr_pages; - dma_addr_t dma_addr; - int ret; - - /* This rounds up number of pages based on size and offset */ - nr_pages = iommu_num_pages(pa, size, PAGE_SIZE); - dma_addr = dma_alloc_address(dev, nr_pages); - if (dma_addr == DMA_MAPPING_ERROR) { - ret = -ENOSPC; - goto out_err; - } - - /* Use rounded up size */ - size = nr_pages * PAGE_SIZE; - - if (direction == DMA_NONE || direction == DMA_TO_DEVICE) - flags |= ZPCI_TABLE_PROTECTED; - - ret = dma_update_trans(zdev, pa, dma_addr, size, flags); - if (ret) - goto out_free; - - atomic64_add(nr_pages, &zdev->mapped_pages); - return dma_addr + (offset & ~PAGE_MASK); - -out_free: - dma_free_address(dev, dma_addr, nr_pages); -out_err: - zpci_err("map error:\n"); - zpci_err_dma(ret, pa); - return DMA_MAPPING_ERROR; -} - -static void s390_dma_unmap_pages(struct device *dev, dma_addr_t dma_addr, - size_t size, enum dma_data_direction direction, - unsigned long attrs) -{ - struct zpci_dev *zdev = to_zpci(to_pci_dev(dev)); - int npages, ret; - - npages = iommu_num_pages(dma_addr, size, PAGE_SIZE); - dma_addr = dma_addr & PAGE_MASK; - ret = dma_update_trans(zdev, 0, dma_addr, npages * PAGE_SIZE, - ZPCI_PTE_INVALID); - if (ret) { - zpci_err("unmap error:\n"); - zpci_err_dma(ret, dma_addr); - return; - } - - atomic64_add(npages, &zdev->unmapped_pages); - dma_free_address(dev, dma_addr, npages); -} - -static void *s390_dma_alloc(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag, - unsigned long attrs) -{ - struct zpci_dev *zdev = to_zpci(to_pci_dev(dev)); - struct page *page; - phys_addr_t pa; - dma_addr_t map; - - size = PAGE_ALIGN(size); - page = alloc_pages(flag | __GFP_ZERO, get_order(size)); - if (!page) - return NULL; - - pa = page_to_phys(page); - map = s390_dma_map_pages(dev, page, 0, size, DMA_BIDIRECTIONAL, 0); - if (dma_mapping_error(dev, map)) { - __free_pages(page, get_order(size)); - return NULL; - } - - atomic64_add(size / PAGE_SIZE, &zdev->allocated_pages); - if (dma_handle) - *dma_handle = map; - return phys_to_virt(pa); -} - -static void s390_dma_free(struct device *dev, size_t size, - void *vaddr, dma_addr_t dma_handle, - unsigned long attrs) -{ - struct zpci_dev *zdev = to_zpci(to_pci_dev(dev)); - - size = PAGE_ALIGN(size); - atomic64_sub(size / PAGE_SIZE, &zdev->allocated_pages); - s390_dma_unmap_pages(dev, dma_handle, size, DMA_BIDIRECTIONAL, 0); - free_pages((unsigned long)vaddr, get_order(size)); -} - -/* Map a segment into a contiguous dma address area */ -static int __s390_dma_map_sg(struct device *dev, struct scatterlist *sg, - size_t size, dma_addr_t *handle, - enum dma_data_direction dir) -{ - unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; - struct zpci_dev *zdev = to_zpci(to_pci_dev(dev)); - dma_addr_t dma_addr_base, dma_addr; - int flags = ZPCI_PTE_VALID; - struct scatterlist *s; - phys_addr_t pa = 0; - int ret; - - dma_addr_base = dma_alloc_address(dev, nr_pages); - if (dma_addr_base == DMA_MAPPING_ERROR) - return -ENOMEM; - - dma_addr = dma_addr_base; - if (dir == DMA_NONE || dir == DMA_TO_DEVICE) - flags |= ZPCI_TABLE_PROTECTED; - - for (s = sg; dma_addr < dma_addr_base + size; s = sg_next(s)) { - pa = page_to_phys(sg_page(s)); - ret = __dma_update_trans(zdev, pa, dma_addr, - s->offset + s->length, flags); - if (ret) - goto unmap; - - dma_addr += s->offset + s->length; - } - ret = __dma_purge_tlb(zdev, dma_addr_base, size, flags); - if (ret) - goto unmap; - - *handle = dma_addr_base; - atomic64_add(nr_pages, &zdev->mapped_pages); - - return ret; - -unmap: - dma_update_trans(zdev, 0, dma_addr_base, dma_addr - dma_addr_base, - ZPCI_PTE_INVALID); - dma_free_address(dev, dma_addr_base, nr_pages); - zpci_err("map error:\n"); - zpci_err_dma(ret, pa); - return ret; -} - -static int s390_dma_map_sg(struct device *dev, struct scatterlist *sg, - int nr_elements, enum dma_data_direction dir, - unsigned long attrs) -{ - struct scatterlist *s = sg, *start = sg, *dma = sg; - unsigned int max = dma_get_max_seg_size(dev); - unsigned int size = s->offset + s->length; - unsigned int offset = s->offset; - int count = 0, i, ret; - - for (i = 1; i < nr_elements; i++) { - s = sg_next(s); - - s->dma_length = 0; - - if (s->offset || (size & ~PAGE_MASK) || - size + s->length > max) { - ret = __s390_dma_map_sg(dev, start, size, - &dma->dma_address, dir); - if (ret) - goto unmap; - - dma->dma_address += offset; - dma->dma_length = size - offset; - - size = offset = s->offset; - start = s; - dma = sg_next(dma); - count++; - } - size += s->length; - } - ret = __s390_dma_map_sg(dev, start, size, &dma->dma_address, dir); - if (ret) - goto unmap; - - dma->dma_address += offset; - dma->dma_length = size - offset; - - return count + 1; -unmap: - for_each_sg(sg, s, count, i) - s390_dma_unmap_pages(dev, sg_dma_address(s), sg_dma_len(s), - dir, attrs); - - return ret; -} - -static void s390_dma_unmap_sg(struct device *dev, struct scatterlist *sg, - int nr_elements, enum dma_data_direction dir, - unsigned long attrs) -{ - struct scatterlist *s; - int i; - - for_each_sg(sg, s, nr_elements, i) { - if (s->dma_length) - s390_dma_unmap_pages(dev, s->dma_address, s->dma_length, - dir, attrs); - s->dma_address = 0; - s->dma_length = 0; - } -} - -int zpci_dma_init_device(struct zpci_dev *zdev) -{ - u8 status; - int rc; - - /* - * At this point, if the device is part of an IOMMU domain, this would - * be a strong hint towards a bug in the IOMMU API (common) code and/or - * simultaneous access via IOMMU and DMA API. So let's issue a warning. - */ - WARN_ON(zdev->s390_domain); - - spin_lock_init(&zdev->iommu_bitmap_lock); - - zdev->dma_table = dma_alloc_cpu_table(GFP_KERNEL); - if (!zdev->dma_table) { - rc = -ENOMEM; - goto out; - } - - /* - * Restrict the iommu bitmap size to the minimum of the following: - * - s390_iommu_aperture which defaults to high_memory - * - 3-level pagetable address limit minus start_dma offset - * - DMA address range allowed by the hardware (clp query pci fn) - * - * Also set zdev->end_dma to the actual end address of the usable - * range, instead of the theoretical maximum as reported by hardware. - * - * This limits the number of concurrently usable DMA mappings since - * for each DMA mapped memory address we need a DMA address including - * extra DMA addresses for multiple mappings of the same memory address. - */ - zdev->start_dma = PAGE_ALIGN(zdev->start_dma); - zdev->iommu_size = min3(s390_iommu_aperture, - ZPCI_TABLE_SIZE_RT - zdev->start_dma, - zdev->end_dma - zdev->start_dma + 1); - zdev->end_dma = zdev->start_dma + zdev->iommu_size - 1; - zdev->iommu_pages = zdev->iommu_size >> PAGE_SHIFT; - zdev->iommu_bitmap = vzalloc(zdev->iommu_pages / 8); - if (!zdev->iommu_bitmap) { - rc = -ENOMEM; - goto free_dma_table; - } - if (!s390_iommu_strict) { - zdev->lazy_bitmap = vzalloc(zdev->iommu_pages / 8); - if (!zdev->lazy_bitmap) { - rc = -ENOMEM; - goto free_bitmap; - } - - } - if (zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, - virt_to_phys(zdev->dma_table), &status)) { - rc = -EIO; - goto free_bitmap; - } - - return 0; -free_bitmap: - vfree(zdev->iommu_bitmap); - zdev->iommu_bitmap = NULL; - vfree(zdev->lazy_bitmap); - zdev->lazy_bitmap = NULL; -free_dma_table: - dma_free_cpu_table(zdev->dma_table); - zdev->dma_table = NULL; -out: - return rc; -} - -int zpci_dma_exit_device(struct zpci_dev *zdev) -{ - int cc = 0; - - /* - * At this point, if the device is part of an IOMMU domain, this would - * be a strong hint towards a bug in the IOMMU API (common) code and/or - * simultaneous access via IOMMU and DMA API. So let's issue a warning. - */ - WARN_ON(zdev->s390_domain); - if (zdev_enabled(zdev)) - cc = zpci_unregister_ioat(zdev, 0); - /* - * cc == 3 indicates the function is gone already. This can happen - * if the function was deconfigured/disabled suddenly and we have not - * received a new handle yet. - */ - if (cc && cc != 3) - return -EIO; - - dma_cleanup_tables(zdev->dma_table); - zdev->dma_table = NULL; - vfree(zdev->iommu_bitmap); - zdev->iommu_bitmap = NULL; - vfree(zdev->lazy_bitmap); - zdev->lazy_bitmap = NULL; - zdev->next_bit = 0; - return 0; -} - -static int __init dma_alloc_cpu_table_caches(void) -{ - dma_region_table_cache = kmem_cache_create("PCI_DMA_region_tables", - ZPCI_TABLE_SIZE, ZPCI_TABLE_ALIGN, - 0, NULL); - if (!dma_region_table_cache) - return -ENOMEM; - - dma_page_table_cache = kmem_cache_create("PCI_DMA_page_tables", - ZPCI_PT_SIZE, ZPCI_PT_ALIGN, - 0, NULL); - if (!dma_page_table_cache) { - kmem_cache_destroy(dma_region_table_cache); - return -ENOMEM; - } - return 0; -} - -int __init zpci_dma_init(void) -{ - s390_iommu_aperture = (u64)virt_to_phys(high_memory); - if (!s390_iommu_aperture_factor) - s390_iommu_aperture = ULONG_MAX; - else - s390_iommu_aperture *= s390_iommu_aperture_factor; - - return dma_alloc_cpu_table_caches(); -} - -void zpci_dma_exit(void) -{ - kmem_cache_destroy(dma_page_table_cache); - kmem_cache_destroy(dma_region_table_cache); -} - -const struct dma_map_ops s390_pci_dma_ops = { - .alloc = s390_dma_alloc, - .free = s390_dma_free, - .map_sg = s390_dma_map_sg, - .unmap_sg = s390_dma_unmap_sg, - .map_page = s390_dma_map_pages, - .unmap_page = s390_dma_unmap_pages, - .mmap = dma_common_mmap, - .get_sgtable = dma_common_get_sgtable, - .alloc_pages = dma_common_alloc_pages, - .free_pages = dma_common_free_pages, - /* dma_supported is unconditionally true without a callback */ -}; -EXPORT_SYMBOL_GPL(s390_pci_dma_ops); - -static int __init s390_iommu_setup(char *str) -{ - if (!strcmp(str, "strict")) - s390_iommu_strict = 1; - return 1; -} - -__setup("s390_iommu=", s390_iommu_setup); - -static int __init s390_iommu_aperture_setup(char *str) -{ - if (kstrtou32(str, 10, &s390_iommu_aperture_factor)) - s390_iommu_aperture_factor = 1; - return 1; -} - -__setup("s390_iommu_aperture=", s390_iommu_aperture_setup); diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c index 4ef5a6a1d6187..4d9773ef9e0a8 100644 --- a/arch/s390/pci/pci_event.c +++ b/arch/s390/pci/pci_event.c @@ -313,8 +313,6 @@ static void zpci_event_hard_deconfigured(struct zpci_dev *zdev, u32 fh) /* Even though the device is already gone we still * need to free zPCI resources as part of the disable. */ - if (zdev->dma_table) - zpci_dma_exit_device(zdev); if (zdev_enabled(zdev)) zpci_disable_device(zdev); zdev->state = ZPCI_FN_STATE_STANDBY; diff --git a/arch/s390/pci/pci_sysfs.c b/arch/s390/pci/pci_sysfs.c index cae280e5c047d..8a7abac518164 100644 --- a/arch/s390/pci/pci_sysfs.c +++ b/arch/s390/pci/pci_sysfs.c @@ -56,6 +56,7 @@ static ssize_t recover_store(struct device *dev, struct device_attribute *attr, struct pci_dev *pdev = to_pci_dev(dev); struct zpci_dev *zdev = to_zpci(pdev); int ret = 0; + u8 status; /* Can't use device_remove_self() here as that would lead us to lock * the pci_rescan_remove_lock while holding the device' kernfs lock. @@ -82,12 +83,6 @@ static ssize_t recover_store(struct device *dev, struct device_attribute *attr, pci_lock_rescan_remove(); if (pci_dev_is_added(pdev)) { pci_stop_and_remove_bus_device(pdev); - if (zdev->dma_table) { - ret = zpci_dma_exit_device(zdev); - if (ret) - goto out; - } - if (zdev_enabled(zdev)) { ret = zpci_disable_device(zdev); /* @@ -105,14 +100,16 @@ static ssize_t recover_store(struct device *dev, struct device_attribute *attr, ret = zpci_enable_device(zdev); if (ret) goto out; - ret = zpci_dma_init_device(zdev); - if (ret) { - zpci_disable_device(zdev); - goto out; + + if (zdev->dma_table) { + ret = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, + virt_to_phys(zdev->dma_table), &status); + if (ret) + zpci_disable_device(zdev); } - pci_rescan_bus(zdev->zbus->bus); } out: + pci_rescan_bus(zdev->zbus->bus); pci_unlock_rescan_remove(); if (kn) sysfs_unbreak_active_protection(kn); diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index cd6727898b117..3199fd54b462c 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -91,7 +91,7 @@ config IOMMU_DEBUGFS choice prompt "IOMMU default domain type" depends on IOMMU_API - default IOMMU_DEFAULT_DMA_LAZY if X86 || IA64 + default IOMMU_DEFAULT_DMA_LAZY if X86 || IA64 || S390 default IOMMU_DEFAULT_DMA_STRICT help Choose the type of IOMMU domain used to manage DMA API usage by @@ -146,7 +146,7 @@ config OF_IOMMU # IOMMU-agnostic DMA-mapping layer config IOMMU_DMA - def_bool ARM64 || IA64 || X86 + def_bool ARM64 || IA64 || X86 || S390 select DMA_OPS select IOMMU_API select IOMMU_IOVA diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c index 560d0957f9bef..bb9e48c826444 100644 --- a/drivers/iommu/s390-iommu.c +++ b/drivers/iommu/s390-iommu.c @@ -14,16 +14,300 @@ #include #include +#include "dma-iommu.h" + static const struct iommu_ops s390_iommu_ops; +static struct kmem_cache *dma_region_table_cache; +static struct kmem_cache *dma_page_table_cache; + +static u64 s390_iommu_aperture; +static u32 s390_iommu_aperture_factor = 1; + struct s390_domain { struct iommu_domain domain; struct list_head devices; + struct zpci_iommu_ctrs ctrs; unsigned long *dma_table; spinlock_t list_lock; struct rcu_head rcu; }; +static inline unsigned int calc_rtx(dma_addr_t ptr) +{ + return ((unsigned long)ptr >> ZPCI_RT_SHIFT) & ZPCI_INDEX_MASK; +} + +static inline unsigned int calc_sx(dma_addr_t ptr) +{ + return ((unsigned long)ptr >> ZPCI_ST_SHIFT) & ZPCI_INDEX_MASK; +} + +static inline unsigned int calc_px(dma_addr_t ptr) +{ + return ((unsigned long)ptr >> PAGE_SHIFT) & ZPCI_PT_MASK; +} + +static inline void set_pt_pfaa(unsigned long *entry, phys_addr_t pfaa) +{ + *entry &= ZPCI_PTE_FLAG_MASK; + *entry |= (pfaa & ZPCI_PTE_ADDR_MASK); +} + +static inline void set_rt_sto(unsigned long *entry, phys_addr_t sto) +{ + *entry &= ZPCI_RTE_FLAG_MASK; + *entry |= (sto & ZPCI_RTE_ADDR_MASK); + *entry |= ZPCI_TABLE_TYPE_RTX; +} + +static inline void set_st_pto(unsigned long *entry, phys_addr_t pto) +{ + *entry &= ZPCI_STE_FLAG_MASK; + *entry |= (pto & ZPCI_STE_ADDR_MASK); + *entry |= ZPCI_TABLE_TYPE_SX; +} + +static inline void validate_rt_entry(unsigned long *entry) +{ + *entry &= ~ZPCI_TABLE_VALID_MASK; + *entry &= ~ZPCI_TABLE_OFFSET_MASK; + *entry |= ZPCI_TABLE_VALID; + *entry |= ZPCI_TABLE_LEN_RTX; +} + +static inline void validate_st_entry(unsigned long *entry) +{ + *entry &= ~ZPCI_TABLE_VALID_MASK; + *entry |= ZPCI_TABLE_VALID; +} + +static inline void invalidate_pt_entry(unsigned long *entry) +{ + WARN_ON_ONCE((*entry & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_INVALID); + *entry &= ~ZPCI_PTE_VALID_MASK; + *entry |= ZPCI_PTE_INVALID; +} + +static inline void validate_pt_entry(unsigned long *entry) +{ + WARN_ON_ONCE((*entry & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID); + *entry &= ~ZPCI_PTE_VALID_MASK; + *entry |= ZPCI_PTE_VALID; +} + +static inline void entry_set_protected(unsigned long *entry) +{ + *entry &= ~ZPCI_TABLE_PROT_MASK; + *entry |= ZPCI_TABLE_PROTECTED; +} + +static inline void entry_clr_protected(unsigned long *entry) +{ + *entry &= ~ZPCI_TABLE_PROT_MASK; + *entry |= ZPCI_TABLE_UNPROTECTED; +} + +static inline int reg_entry_isvalid(unsigned long entry) +{ + return (entry & ZPCI_TABLE_VALID_MASK) == ZPCI_TABLE_VALID; +} + +static inline int pt_entry_isvalid(unsigned long entry) +{ + return (entry & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID; +} + +static inline unsigned long *get_rt_sto(unsigned long entry) +{ + if ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_RTX) + return phys_to_virt(entry & ZPCI_RTE_ADDR_MASK); + else + return NULL; +} + +static inline unsigned long *get_st_pto(unsigned long entry) +{ + if ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_SX) + return phys_to_virt(entry & ZPCI_STE_ADDR_MASK); + else + return NULL; +} + +static int __init dma_alloc_cpu_table_caches(void) +{ + dma_region_table_cache = kmem_cache_create("PCI_DMA_region_tables", + ZPCI_TABLE_SIZE, + ZPCI_TABLE_ALIGN, + 0, NULL); + if (!dma_region_table_cache) + return -ENOMEM; + + dma_page_table_cache = kmem_cache_create("PCI_DMA_page_tables", + ZPCI_PT_SIZE, + ZPCI_PT_ALIGN, + 0, NULL); + if (!dma_page_table_cache) { + kmem_cache_destroy(dma_region_table_cache); + return -ENOMEM; + } + return 0; +} + +static unsigned long *dma_alloc_cpu_table(gfp_t gfp) +{ + unsigned long *table, *entry; + + table = kmem_cache_alloc(dma_region_table_cache, gfp); + if (!table) + return NULL; + + for (entry = table; entry < table + ZPCI_TABLE_ENTRIES; entry++) + *entry = ZPCI_TABLE_INVALID; + return table; +} + +static void dma_free_cpu_table(void *table) +{ + kmem_cache_free(dma_region_table_cache, table); +} + +static void dma_free_page_table(void *table) +{ + kmem_cache_free(dma_page_table_cache, table); +} + +static void dma_free_seg_table(unsigned long entry) +{ + unsigned long *sto = get_rt_sto(entry); + int sx; + + for (sx = 0; sx < ZPCI_TABLE_ENTRIES; sx++) + if (reg_entry_isvalid(sto[sx])) + dma_free_page_table(get_st_pto(sto[sx])); + + dma_free_cpu_table(sto); +} + +static void dma_cleanup_tables(unsigned long *table) +{ + int rtx; + + if (!table) + return; + + for (rtx = 0; rtx < ZPCI_TABLE_ENTRIES; rtx++) + if (reg_entry_isvalid(table[rtx])) + dma_free_seg_table(table[rtx]); + + dma_free_cpu_table(table); +} + +static unsigned long *dma_alloc_page_table(gfp_t gfp) +{ + unsigned long *table, *entry; + + table = kmem_cache_alloc(dma_page_table_cache, gfp); + if (!table) + return NULL; + + for (entry = table; entry < table + ZPCI_PT_ENTRIES; entry++) + *entry = ZPCI_PTE_INVALID; + return table; +} + +static unsigned long *dma_get_seg_table_origin(unsigned long *rtep, gfp_t gfp) +{ + unsigned long old_rte, rte; + unsigned long *sto; + + rte = READ_ONCE(*rtep); + if (reg_entry_isvalid(rte)) { + sto = get_rt_sto(rte); + } else { + sto = dma_alloc_cpu_table(gfp); + if (!sto) + return NULL; + + set_rt_sto(&rte, virt_to_phys(sto)); + validate_rt_entry(&rte); + entry_clr_protected(&rte); + + old_rte = cmpxchg(rtep, ZPCI_TABLE_INVALID, rte); + if (old_rte != ZPCI_TABLE_INVALID) { + /* Somone else was faster, use theirs */ + dma_free_cpu_table(sto); + sto = get_rt_sto(old_rte); + } + } + return sto; +} + +static unsigned long *dma_get_page_table_origin(unsigned long *step, gfp_t gfp) +{ + unsigned long old_ste, ste; + unsigned long *pto; + + ste = READ_ONCE(*step); + if (reg_entry_isvalid(ste)) { + pto = get_st_pto(ste); + } else { + pto = dma_alloc_page_table(gfp); + if (!pto) + return NULL; + set_st_pto(&ste, virt_to_phys(pto)); + validate_st_entry(&ste); + entry_clr_protected(&ste); + + old_ste = cmpxchg(step, ZPCI_TABLE_INVALID, ste); + if (old_ste != ZPCI_TABLE_INVALID) { + /* Somone else was faster, use theirs */ + dma_free_page_table(pto); + pto = get_st_pto(old_ste); + } + } + return pto; +} + +static unsigned long *dma_walk_cpu_trans(unsigned long *rto, dma_addr_t dma_addr, gfp_t gfp) +{ + unsigned long *sto, *pto; + unsigned int rtx, sx, px; + + rtx = calc_rtx(dma_addr); + sto = dma_get_seg_table_origin(&rto[rtx], gfp); + if (!sto) + return NULL; + + sx = calc_sx(dma_addr); + pto = dma_get_page_table_origin(&sto[sx], gfp); + if (!pto) + return NULL; + + px = calc_px(dma_addr); + return &pto[px]; +} + +static void dma_update_cpu_trans(unsigned long *ptep, phys_addr_t page_addr, int flags) +{ + unsigned long pte; + + pte = READ_ONCE(*ptep); + if (flags & ZPCI_PTE_INVALID) { + invalidate_pt_entry(&pte); + } else { + set_pt_pfaa(&pte, page_addr); + validate_pt_entry(&pte); + } + + if (flags & ZPCI_TABLE_PROTECTED) + entry_set_protected(&pte); + else + entry_clr_protected(&pte); + + xchg(ptep, pte); +} + static struct s390_domain *to_s390_domain(struct iommu_domain *dom) { return container_of(dom, struct s390_domain, domain); @@ -34,6 +318,8 @@ static bool s390_iommu_capable(struct device *dev, enum iommu_cap cap) switch (cap) { case IOMMU_CAP_CACHE_COHERENCY: return true; + case IOMMU_CAP_DEFERRED_FLUSH: + return true; default: return false; } @@ -81,14 +367,13 @@ static void s390_domain_free(struct iommu_domain *domain) call_rcu(&s390_domain->rcu, s390_iommu_rcu_free_domain); } -static void __s390_iommu_detach_device(struct zpci_dev *zdev) +static void s390_iommu_detach_device(struct iommu_domain *domain, + struct device *dev) { - struct s390_domain *s390_domain = zdev->s390_domain; + struct s390_domain *s390_domain = to_s390_domain(domain); + struct zpci_dev *zdev = to_zpci_dev(dev); unsigned long flags; - if (!s390_domain) - return; - spin_lock_irqsave(&s390_domain->list_lock, flags); list_del_rcu(&zdev->iommu_list); spin_unlock_irqrestore(&s390_domain->list_lock, flags); @@ -115,9 +400,7 @@ static int s390_iommu_attach_device(struct iommu_domain *domain, return -EINVAL; if (zdev->s390_domain) - __s390_iommu_detach_device(zdev); - else if (zdev->dma_table) - zpci_dma_exit_device(zdev); + s390_iommu_detach_device(&zdev->s390_domain->domain, dev); cc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, virt_to_phys(s390_domain->dma_table), &status); @@ -127,7 +410,6 @@ static int s390_iommu_attach_device(struct iommu_domain *domain, */ if (cc && status != ZPCI_PCI_ST_FUNC_NOT_AVAIL) return -EIO; - zdev->dma_table = s390_domain->dma_table; zdev->dma_table = s390_domain->dma_table; zdev->s390_domain = s390_domain; @@ -139,31 +421,6 @@ static int s390_iommu_attach_device(struct iommu_domain *domain, return 0; } -/* - * Switch control over the IOMMU to S390's internal dma_api ops - */ -static int s390_iommu_platform_attach(struct iommu_domain *platform_domain, - struct device *dev) -{ - struct zpci_dev *zdev = to_zpci_dev(dev); - - if (!zdev->s390_domain) - return 0; - - __s390_iommu_detach_device(zdev); - zpci_dma_init_device(zdev); - return 0; -} - -static struct iommu_domain_ops s390_iommu_platform_ops = { - .attach_dev = s390_iommu_platform_attach, -}; - -static struct iommu_domain s390_iommu_platform_domain = { - .type = IOMMU_DOMAIN_PLATFORM, - .ops = &s390_iommu_platform_ops, -}; - static void s390_iommu_get_resv_regions(struct device *dev, struct list_head *list) { @@ -216,7 +473,7 @@ static void s390_iommu_release_device(struct device *dev) * to the device, but keep it attached to other devices in the group. */ if (zdev) - __s390_iommu_detach_device(zdev); + s390_iommu_detach_device(&zdev->s390_domain->domain, dev); } static int zpci_refresh_all(struct zpci_dev *zdev) @@ -232,6 +489,7 @@ static void s390_iommu_flush_iotlb_all(struct iommu_domain *domain) rcu_read_lock(); list_for_each_entry_rcu(zdev, &s390_domain->devices, iommu_list) { + atomic64_inc(&s390_domain->ctrs.global_rpcits); zpci_refresh_all(zdev); } rcu_read_unlock(); @@ -250,6 +508,7 @@ static void s390_iommu_iotlb_sync(struct iommu_domain *domain, rcu_read_lock(); list_for_each_entry_rcu(zdev, &s390_domain->devices, iommu_list) { + atomic64_inc(&s390_domain->ctrs.sync_rpcits); zpci_refresh_trans((u64)zdev->fh << 32, gather->start, size); } @@ -267,6 +526,7 @@ static int s390_iommu_iotlb_sync_map(struct iommu_domain *domain, list_for_each_entry_rcu(zdev, &s390_domain->devices, iommu_list) { if (!zdev->tlb_refresh) continue; + atomic64_inc(&s390_domain->ctrs.sync_map_rpcits); ret = zpci_refresh_trans((u64)zdev->fh << 32, iova, size); /* @@ -361,16 +621,15 @@ static int s390_iommu_map_pages(struct iommu_domain *domain, if (!IS_ALIGNED(iova | paddr, pgsize)) return -EINVAL; - if (!(prot & IOMMU_READ)) - return -EINVAL; - if (!(prot & IOMMU_WRITE)) flags |= ZPCI_TABLE_PROTECTED; rc = s390_iommu_validate_trans(s390_domain, paddr, iova, - pgcount, flags, gfp); - if (!rc) + pgcount, flags, gfp); + if (!rc) { *mapped = size; + atomic64_add(pgcount, &s390_domain->ctrs.mapped_pages); + } return rc; } @@ -426,12 +685,26 @@ static size_t s390_iommu_unmap_pages(struct iommu_domain *domain, return 0; iommu_iotlb_gather_add_range(gather, iova, size); + atomic64_add(pgcount, &s390_domain->ctrs.unmapped_pages); return size; } +static void s390_iommu_probe_finalize(struct device *dev) +{ + iommu_setup_dma_ops(dev, 0, U64_MAX); +} + +struct zpci_iommu_ctrs *zpci_get_iommu_ctrs(struct zpci_dev *zdev) +{ + if (!zdev || !zdev->s390_domain) + return NULL; + return &zdev->s390_domain->ctrs; +} + int zpci_init_iommu(struct zpci_dev *zdev) { + u64 aperture_size; int rc = 0; rc = iommu_device_sysfs_add(&zdev->iommu_dev, NULL, NULL, @@ -443,6 +716,12 @@ int zpci_init_iommu(struct zpci_dev *zdev) if (rc) goto out_sysfs; + zdev->start_dma = PAGE_ALIGN(zdev->start_dma); + aperture_size = min3(s390_iommu_aperture, + ZPCI_TABLE_SIZE_RT - zdev->start_dma, + zdev->end_dma - zdev->start_dma + 1); + zdev->end_dma = zdev->start_dma + aperture_size - 1; + return 0; out_sysfs: @@ -458,11 +737,50 @@ void zpci_destroy_iommu(struct zpci_dev *zdev) iommu_device_sysfs_remove(&zdev->iommu_dev); } +static int __init s390_iommu_setup(char *str) +{ + if (!strcmp(str, "strict")) { + pr_warn("s390_iommu=strict deprecated; use iommu.strict=1 instead\n"); + iommu_set_dma_strict(); + } + return 1; +} + +__setup("s390_iommu=", s390_iommu_setup); + +static int __init s390_iommu_aperture_setup(char *str) +{ + if (kstrtou32(str, 10, &s390_iommu_aperture_factor)) + s390_iommu_aperture_factor = 1; + return 1; +} + +__setup("s390_iommu_aperture=", s390_iommu_aperture_setup); + +static int __init s390_iommu_init(void) +{ + int rc; + + iommu_dma_forcedac = true; + s390_iommu_aperture = (u64)virt_to_phys(high_memory); + if (!s390_iommu_aperture_factor) + s390_iommu_aperture = ULONG_MAX; + else + s390_iommu_aperture *= s390_iommu_aperture_factor; + + rc = dma_alloc_cpu_table_caches(); + if (rc) + return rc; + + return rc; +} +subsys_initcall(s390_iommu_init); + static const struct iommu_ops s390_iommu_ops = { - .default_domain = &s390_iommu_platform_domain, .capable = s390_iommu_capable, .domain_alloc_paging = s390_domain_alloc_paging, .probe_device = s390_iommu_probe_device, + .probe_finalize = s390_iommu_probe_finalize, .release_device = s390_iommu_release_device, .device_group = generic_device_group, .pgsize_bitmap = SZ_4K, -- GitLab From 53f8e9ad7653eefe250834511e34cdef3d1c444e Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Thu, 28 Sep 2023 16:31:38 +0200 Subject: [PATCH 0399/1451] iommu/s390: Disable deferred flush for ISM devices ISM devices are virtual PCI devices used for cross-LPAR communication. Unlike real PCI devices ISM devices do not use the hardware IOMMU but inspects IOMMU translation tables directly on IOTLB flush (s390 RPCIT instruction). ISM devices keep their DMA allocations static and only very rarely DMA unmap at all. For each IOTLB flush that occurs after unmap the ISM devices will however inspect the area of the IOVA space indicated by the flush. This means that for the global IOTLB flushes used by the flush queue mechanism the entire IOVA space would be inspected. In principle this would be fine, albeit potentially unnecessarily slow, it turns out however that ISM devices are sensitive to seeing IOVA addresses that are currently in use in the IOVA range being flushed. Seeing such in-use IOVA addresses will cause the ISM device to enter an error state and become unusable. Fix this by claiming IOMMU_CAP_DEFERRED_FLUSH only for non-ISM devices. This makes sure IOTLB flushes only cover IOVAs that have been unmapped and also restricts the range of the IOTLB flush potentially reducing latency spikes. Signed-off-by: Niklas Schnelle Reviewed-by: Matthew Rosato Link: https://lore.kernel.org/r/20230928-dma_iommu-v13-4-9e5fc4dacc36@linux.ibm.com Signed-off-by: Joerg Roedel --- drivers/iommu/s390-iommu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c index bb9e48c826444..5b5ba1cd5f00a 100644 --- a/drivers/iommu/s390-iommu.c +++ b/drivers/iommu/s390-iommu.c @@ -315,11 +315,13 @@ static struct s390_domain *to_s390_domain(struct iommu_domain *dom) static bool s390_iommu_capable(struct device *dev, enum iommu_cap cap) { + struct zpci_dev *zdev = to_zpci_dev(dev); + switch (cap) { case IOMMU_CAP_CACHE_COHERENCY: return true; case IOMMU_CAP_DEFERRED_FLUSH: - return true; + return zdev->pft != PCI_FUNC_TYPE_ISM; default: return false; } -- GitLab From 32d5bc8b09c7cc48c511809e7c3b1755c7ecc5fa Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Thu, 28 Sep 2023 16:31:39 +0200 Subject: [PATCH 0400/1451] iommu/dma: Allow a single FQ in addition to per-CPU FQs In some virtualized environments, including s390 paged memory guests, IOTLB flushes are used to update IOMMU shadow tables. Due to this, they are much more expensive than in typical bare metal environments or non-paged s390 guests. In addition they may parallelize poorly in virtualized environments. This changes the trade off for flushing IOVAs such that minimizing the number of IOTLB flushes trumps any benefit of cheaper queuing operations or increased paralellism. In this scenario per-CPU flush queues pose several problems. Firstly per-CPU memory is often quite limited prohibiting larger queues. Secondly collecting IOVAs per-CPU but flushing via a global timeout reduces the number of IOVAs flushed for each timeout especially on s390 where PCI interrupts may not be bound to a specific CPU. Let's introduce a single flush queue mode that reuses the same queue logic but only allocates a single global queue. This mode is selected by dma-iommu if a newly introduced .shadow_on_flush flag is set in struct dev_iommu. As a first user the s390 IOMMU driver sets this flag during probe_device. With the unchanged small FQ size and timeouts this setting is worse than per-CPU queues but a follow up patch will make the FQ size and timeout variable. Together this allows the common IOVA flushing code to more closely resemble the global flush behavior used on s390's previous internal DMA API implementation. Link: https://lore.kernel.org/all/9a466109-01c5-96b0-bf03-304123f435ee@arm.com/ Acked-by: Robin Murphy Reviewed-by: Matthew Rosato #s390 Signed-off-by: Niklas Schnelle Link: https://lore.kernel.org/r/20230928-dma_iommu-v13-5-9e5fc4dacc36@linux.ibm.com Signed-off-by: Joerg Roedel --- drivers/iommu/dma-iommu.c | 168 ++++++++++++++++++++++++++++--------- drivers/iommu/s390-iommu.c | 3 + include/linux/iommu.h | 2 + 3 files changed, 134 insertions(+), 39 deletions(-) diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 4b1a88f514c9c..a85ff75ad531c 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -43,14 +43,26 @@ enum iommu_dma_cookie_type { IOMMU_DMA_MSI_COOKIE, }; +enum iommu_dma_queue_type { + IOMMU_DMA_OPTS_PER_CPU_QUEUE, + IOMMU_DMA_OPTS_SINGLE_QUEUE, +}; + +struct iommu_dma_options { + enum iommu_dma_queue_type qt; +}; + struct iommu_dma_cookie { enum iommu_dma_cookie_type type; union { /* Full allocator for IOMMU_DMA_IOVA_COOKIE */ struct { struct iova_domain iovad; - - struct iova_fq __percpu *fq; /* Flush queue */ + /* Flush queue */ + union { + struct iova_fq *single_fq; + struct iova_fq __percpu *percpu_fq; + }; /* Number of TLB flushes that have been started */ atomic64_t fq_flush_start_cnt; /* Number of TLB flushes that have been finished */ @@ -67,6 +79,8 @@ struct iommu_dma_cookie { /* Domain for flush queue callback; NULL if flush queue not in use */ struct iommu_domain *fq_domain; + /* Options for dma-iommu use */ + struct iommu_dma_options options; struct mutex mutex; }; @@ -124,7 +138,7 @@ static inline unsigned int fq_ring_add(struct iova_fq *fq) return idx; } -static void fq_ring_free(struct iommu_dma_cookie *cookie, struct iova_fq *fq) +static void fq_ring_free_locked(struct iommu_dma_cookie *cookie, struct iova_fq *fq) { u64 counter = atomic64_read(&cookie->fq_flush_finish_cnt); unsigned int idx; @@ -145,6 +159,15 @@ static void fq_ring_free(struct iommu_dma_cookie *cookie, struct iova_fq *fq) } } +static void fq_ring_free(struct iommu_dma_cookie *cookie, struct iova_fq *fq) +{ + unsigned long flags; + + spin_lock_irqsave(&fq->lock, flags); + fq_ring_free_locked(cookie, fq); + spin_unlock_irqrestore(&fq->lock, flags); +} + static void fq_flush_iotlb(struct iommu_dma_cookie *cookie) { atomic64_inc(&cookie->fq_flush_start_cnt); @@ -160,14 +183,11 @@ static void fq_flush_timeout(struct timer_list *t) atomic_set(&cookie->fq_timer_on, 0); fq_flush_iotlb(cookie); - for_each_possible_cpu(cpu) { - unsigned long flags; - struct iova_fq *fq; - - fq = per_cpu_ptr(cookie->fq, cpu); - spin_lock_irqsave(&fq->lock, flags); - fq_ring_free(cookie, fq); - spin_unlock_irqrestore(&fq->lock, flags); + if (cookie->options.qt == IOMMU_DMA_OPTS_SINGLE_QUEUE) { + fq_ring_free(cookie, cookie->single_fq); + } else { + for_each_possible_cpu(cpu) + fq_ring_free(cookie, per_cpu_ptr(cookie->percpu_fq, cpu)); } } @@ -188,7 +208,11 @@ static void queue_iova(struct iommu_dma_cookie *cookie, */ smp_mb(); - fq = raw_cpu_ptr(cookie->fq); + if (cookie->options.qt == IOMMU_DMA_OPTS_SINGLE_QUEUE) + fq = cookie->single_fq; + else + fq = raw_cpu_ptr(cookie->percpu_fq); + spin_lock_irqsave(&fq->lock, flags); /* @@ -196,11 +220,11 @@ static void queue_iova(struct iommu_dma_cookie *cookie, * flushed out on another CPU. This makes the fq_full() check below less * likely to be true. */ - fq_ring_free(cookie, fq); + fq_ring_free_locked(cookie, fq); if (fq_full(fq)) { fq_flush_iotlb(cookie); - fq_ring_free(cookie, fq); + fq_ring_free_locked(cookie, fq); } idx = fq_ring_add(fq); @@ -219,31 +243,88 @@ static void queue_iova(struct iommu_dma_cookie *cookie, jiffies + msecs_to_jiffies(IOVA_FQ_TIMEOUT)); } -static void iommu_dma_free_fq(struct iommu_dma_cookie *cookie) +static void iommu_dma_free_fq_single(struct iova_fq *fq) { - int cpu, idx; + int idx; - if (!cookie->fq) - return; + fq_ring_for_each(idx, fq) + put_pages_list(&fq->entries[idx].freelist); + vfree(fq); +} + +static void iommu_dma_free_fq_percpu(struct iova_fq __percpu *percpu_fq) +{ + int cpu, idx; - del_timer_sync(&cookie->fq_timer); /* The IOVAs will be torn down separately, so just free our queued pages */ for_each_possible_cpu(cpu) { - struct iova_fq *fq = per_cpu_ptr(cookie->fq, cpu); + struct iova_fq *fq = per_cpu_ptr(percpu_fq, cpu); fq_ring_for_each(idx, fq) put_pages_list(&fq->entries[idx].freelist); } - free_percpu(cookie->fq); + free_percpu(percpu_fq); +} + +static void iommu_dma_free_fq(struct iommu_dma_cookie *cookie) +{ + if (!cookie->fq_domain) + return; + + del_timer_sync(&cookie->fq_timer); + if (cookie->options.qt == IOMMU_DMA_OPTS_SINGLE_QUEUE) + iommu_dma_free_fq_single(cookie->single_fq); + else + iommu_dma_free_fq_percpu(cookie->percpu_fq); +} + +static void iommu_dma_init_one_fq(struct iova_fq *fq) +{ + int i; + + fq->head = 0; + fq->tail = 0; + + spin_lock_init(&fq->lock); + + for (i = 0; i < IOVA_FQ_SIZE; i++) + INIT_LIST_HEAD(&fq->entries[i].freelist); +} + +static int iommu_dma_init_fq_single(struct iommu_dma_cookie *cookie) +{ + struct iova_fq *queue; + + queue = vmalloc(sizeof(*queue)); + if (!queue) + return -ENOMEM; + iommu_dma_init_one_fq(queue); + cookie->single_fq = queue; + + return 0; +} + +static int iommu_dma_init_fq_percpu(struct iommu_dma_cookie *cookie) +{ + struct iova_fq __percpu *queue; + int cpu; + + queue = alloc_percpu(struct iova_fq); + if (!queue) + return -ENOMEM; + + for_each_possible_cpu(cpu) + iommu_dma_init_one_fq(per_cpu_ptr(queue, cpu)); + cookie->percpu_fq = queue; + return 0; } /* sysfs updates are serialised by the mutex of the group owning @domain */ int iommu_dma_init_fq(struct iommu_domain *domain) { struct iommu_dma_cookie *cookie = domain->iova_cookie; - struct iova_fq __percpu *queue; - int i, cpu; + int rc; if (cookie->fq_domain) return 0; @@ -251,26 +332,16 @@ int iommu_dma_init_fq(struct iommu_domain *domain) atomic64_set(&cookie->fq_flush_start_cnt, 0); atomic64_set(&cookie->fq_flush_finish_cnt, 0); - queue = alloc_percpu(struct iova_fq); - if (!queue) { + if (cookie->options.qt == IOMMU_DMA_OPTS_SINGLE_QUEUE) + rc = iommu_dma_init_fq_single(cookie); + else + rc = iommu_dma_init_fq_percpu(cookie); + + if (rc) { pr_warn("iova flush queue initialization failed\n"); return -ENOMEM; } - for_each_possible_cpu(cpu) { - struct iova_fq *fq = per_cpu_ptr(queue, cpu); - - fq->head = 0; - fq->tail = 0; - - spin_lock_init(&fq->lock); - - for (i = 0; i < IOVA_FQ_SIZE; i++) - INIT_LIST_HEAD(&fq->entries[i].freelist); - } - - cookie->fq = queue; - timer_setup(&cookie->fq_timer, fq_flush_timeout, 0); atomic_set(&cookie->fq_timer_on, 0); /* @@ -554,6 +625,23 @@ static bool dev_use_sg_swiotlb(struct device *dev, struct scatterlist *sg, return false; } +/** + * iommu_dma_init_options - Initialize dma-iommu options + * @options: The options to be initialized + * @dev: Device the options are set for + * + * This allows tuning dma-iommu specific to device properties + */ +static void iommu_dma_init_options(struct iommu_dma_options *options, + struct device *dev) +{ + /* Shadowing IOTLB flushes do better with a single queue */ + if (dev->iommu->shadow_on_flush) + options->qt = IOMMU_DMA_OPTS_SINGLE_QUEUE; + else + options->qt = IOMMU_DMA_OPTS_PER_CPU_QUEUE; +} + /** * iommu_dma_init_domain - Initialise a DMA mapping domain * @domain: IOMMU domain previously prepared by iommu_get_dma_cookie() @@ -614,6 +702,8 @@ static int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, if (ret) goto done_unlock; + iommu_dma_init_options(&cookie->options, dev); + /* If the FQ fails we can simply fall back to strict mode */ if (domain->type == IOMMU_DOMAIN_DMA_FQ && (!device_iommu_capable(dev, IOMMU_CAP_DEFERRED_FLUSH) || iommu_dma_init_fq(domain))) diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c index 5b5ba1cd5f00a..9a5196f523de5 100644 --- a/drivers/iommu/s390-iommu.c +++ b/drivers/iommu/s390-iommu.c @@ -463,6 +463,9 @@ static struct iommu_device *s390_iommu_probe_device(struct device *dev) if (zdev->end_dma > ZPCI_TABLE_SIZE_RT - 1) zdev->end_dma = ZPCI_TABLE_SIZE_RT - 1; + if (zdev->tlb_refresh) + dev->iommu->shadow_on_flush = 1; + return &zdev->iommu_dev; } diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 1eb6387527810..0c4d8ae985ac6 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -424,6 +424,7 @@ struct iommu_fault_param { * @attach_deferred: the dma domain attachment is deferred * @pci_32bit_workaround: Limit DMA allocations to 32-bit IOVAs * @require_direct: device requires IOMMU_RESV_DIRECT regions + * @shadow_on_flush: IOTLB flushes are used to sync shadow tables * * TODO: migrate other per device data pointers under iommu_dev_data, e.g. * struct iommu_group *iommu_group; @@ -439,6 +440,7 @@ struct dev_iommu { u32 attach_deferred:1; u32 pci_32bit_workaround:1; u32 require_direct:1; + u32 shadow_on_flush:1; }; int iommu_device_register(struct iommu_device *iommu, -- GitLab From 9f5b681e2a3f7d5bab02e68f3e68a50b23968c7c Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Thu, 28 Sep 2023 16:31:40 +0200 Subject: [PATCH 0401/1451] iommu/dma: Use a large flush queue and timeout for shadow_on_flush Flush queues currently use a fixed compile time size of 256 entries. This being a power of 2 allows the compiler to use shift and mask instead of more expensive modulo operations. With per-CPU flush queues larger queue sizes would hit per-CPU allocation limits, with a single flush queue these limits do not apply however. Also with single queues being particularly suitable for virtualized environments with expensive IOTLB flushes these benefit especially from larger queues and thus fewer flushes. To this end re-order struct iova_fq so we can use a dynamic array and introduce the flush queue size and timeouts as new options in the iommu_dma_options struct. So as not to lose the shift and mask optimization, use a power of 2 for the length and use explicit shift and mask instead of letting the compiler optimize this. A large queue size and 1 second timeout is then set for the shadow on flush case set by s390 paged memory guests. This then brings performance on par with the previous s390 specific DMA API implementation. Acked-by: Robin Murphy Reviewed-by: Matthew Rosato #s390 Signed-off-by: Niklas Schnelle Link: https://lore.kernel.org/r/20230928-dma_iommu-v13-6-9e5fc4dacc36@linux.ibm.com Signed-off-by: Joerg Roedel --- drivers/iommu/dma-iommu.c | 50 +++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index a85ff75ad531c..85163a83df2f6 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -50,6 +50,8 @@ enum iommu_dma_queue_type { struct iommu_dma_options { enum iommu_dma_queue_type qt; + size_t fq_size; + unsigned int fq_timeout; }; struct iommu_dma_cookie { @@ -98,10 +100,12 @@ static int __init iommu_dma_forcedac_setup(char *str) early_param("iommu.forcedac", iommu_dma_forcedac_setup); /* Number of entries per flush queue */ -#define IOVA_FQ_SIZE 256 +#define IOVA_DEFAULT_FQ_SIZE 256 +#define IOVA_SINGLE_FQ_SIZE 32768 /* Timeout (in ms) after which entries are flushed from the queue */ -#define IOVA_FQ_TIMEOUT 10 +#define IOVA_DEFAULT_FQ_TIMEOUT 10 +#define IOVA_SINGLE_FQ_TIMEOUT 1000 /* Flush queue entry for deferred flushing */ struct iova_fq_entry { @@ -113,18 +117,19 @@ struct iova_fq_entry { /* Per-CPU flush queue structure */ struct iova_fq { - struct iova_fq_entry entries[IOVA_FQ_SIZE]; - unsigned int head, tail; spinlock_t lock; + unsigned int head, tail; + unsigned int mod_mask; + struct iova_fq_entry entries[]; }; #define fq_ring_for_each(i, fq) \ - for ((i) = (fq)->head; (i) != (fq)->tail; (i) = ((i) + 1) % IOVA_FQ_SIZE) + for ((i) = (fq)->head; (i) != (fq)->tail; (i) = ((i) + 1) & (fq)->mod_mask) static inline bool fq_full(struct iova_fq *fq) { assert_spin_locked(&fq->lock); - return (((fq->tail + 1) % IOVA_FQ_SIZE) == fq->head); + return (((fq->tail + 1) & fq->mod_mask) == fq->head); } static inline unsigned int fq_ring_add(struct iova_fq *fq) @@ -133,7 +138,7 @@ static inline unsigned int fq_ring_add(struct iova_fq *fq) assert_spin_locked(&fq->lock); - fq->tail = (idx + 1) % IOVA_FQ_SIZE; + fq->tail = (idx + 1) & fq->mod_mask; return idx; } @@ -155,7 +160,7 @@ static void fq_ring_free_locked(struct iommu_dma_cookie *cookie, struct iova_fq fq->entries[idx].iova_pfn, fq->entries[idx].pages); - fq->head = (fq->head + 1) % IOVA_FQ_SIZE; + fq->head = (fq->head + 1) & fq->mod_mask; } } @@ -240,7 +245,7 @@ static void queue_iova(struct iommu_dma_cookie *cookie, if (!atomic_read(&cookie->fq_timer_on) && !atomic_xchg(&cookie->fq_timer_on, 1)) mod_timer(&cookie->fq_timer, - jiffies + msecs_to_jiffies(IOVA_FQ_TIMEOUT)); + jiffies + msecs_to_jiffies(cookie->options.fq_timeout)); } static void iommu_dma_free_fq_single(struct iova_fq *fq) @@ -279,27 +284,29 @@ static void iommu_dma_free_fq(struct iommu_dma_cookie *cookie) iommu_dma_free_fq_percpu(cookie->percpu_fq); } -static void iommu_dma_init_one_fq(struct iova_fq *fq) +static void iommu_dma_init_one_fq(struct iova_fq *fq, size_t fq_size) { int i; fq->head = 0; fq->tail = 0; + fq->mod_mask = fq_size - 1; spin_lock_init(&fq->lock); - for (i = 0; i < IOVA_FQ_SIZE; i++) + for (i = 0; i < fq_size; i++) INIT_LIST_HEAD(&fq->entries[i].freelist); } static int iommu_dma_init_fq_single(struct iommu_dma_cookie *cookie) { + size_t fq_size = cookie->options.fq_size; struct iova_fq *queue; - queue = vmalloc(sizeof(*queue)); + queue = vmalloc(struct_size(queue, entries, fq_size)); if (!queue) return -ENOMEM; - iommu_dma_init_one_fq(queue); + iommu_dma_init_one_fq(queue, fq_size); cookie->single_fq = queue; return 0; @@ -307,15 +314,17 @@ static int iommu_dma_init_fq_single(struct iommu_dma_cookie *cookie) static int iommu_dma_init_fq_percpu(struct iommu_dma_cookie *cookie) { + size_t fq_size = cookie->options.fq_size; struct iova_fq __percpu *queue; int cpu; - queue = alloc_percpu(struct iova_fq); + queue = __alloc_percpu(struct_size(queue, entries, fq_size), + __alignof__(*queue)); if (!queue) return -ENOMEM; for_each_possible_cpu(cpu) - iommu_dma_init_one_fq(per_cpu_ptr(queue, cpu)); + iommu_dma_init_one_fq(per_cpu_ptr(queue, cpu), fq_size); cookie->percpu_fq = queue; return 0; } @@ -635,11 +644,16 @@ static bool dev_use_sg_swiotlb(struct device *dev, struct scatterlist *sg, static void iommu_dma_init_options(struct iommu_dma_options *options, struct device *dev) { - /* Shadowing IOTLB flushes do better with a single queue */ - if (dev->iommu->shadow_on_flush) + /* Shadowing IOTLB flushes do better with a single large queue */ + if (dev->iommu->shadow_on_flush) { options->qt = IOMMU_DMA_OPTS_SINGLE_QUEUE; - else + options->fq_timeout = IOVA_SINGLE_FQ_TIMEOUT; + options->fq_size = IOVA_SINGLE_FQ_SIZE; + } else { options->qt = IOMMU_DMA_OPTS_PER_CPU_QUEUE; + options->fq_size = IOVA_DEFAULT_FQ_SIZE; + options->fq_timeout = IOVA_DEFAULT_FQ_TIMEOUT; + } } /** -- GitLab From 4c6a08125f2249531ec01783a5f4317d7342add5 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Thu, 21 Sep 2023 08:46:43 -0500 Subject: [PATCH 0402/1451] gfs2: ignore negated quota changes When lots of quota changes are made, there may be cases in which an inode's quota information is increased and then decreased, such as when blocks are added to a file, then deleted from it. If the timing is right, function do_qc can add pending quota changes to a transaction, then later, another call to do_qc can negate those changes, resulting in a net gain of 0. The quota_change information is recorded in the qc buffer (and qd element of the inode as well). The buffer is added to the transaction by the first call to do_qc, but a subsequent call changes the value from non-zero back to zero. At that point it's too late to remove the buffer_head from the transaction. Later, when the quota sync code is called, the zero-change qd element is discovered and flagged as an assert warning. If the fs is mounted with errors=panic, the kernel will panic. This is usually seen when files are truncated and the quota changes are negated by punch_hole/truncate which uses gfs2_quota_hold and gfs2_quota_unhold rather than block allocations that use gfs2_quota_lock and gfs2_quota_unlock which automatically do quota sync. This patch solves the problem by adding a check to qd_check_sync such that net-zero quota changes already added to the transaction are no longer deemed necessary to be synced, and skipped. In this case references are taken for the qd and the slot from do_qc so those need to be put. The normal sequence of events for a normal non-zero quota change is as follows: gfs2_quota_change do_qc qd_hold slot_hold Later, when the changes are to be synced: gfs2_quota_sync qd_fish qd_check_sync gets qd ref via lockref_get_not_dead do_sync do_qc(QC_SYNC) qd_put lockref_put_or_lock qd_unlock qd_put lockref_put_or_lock In the net-zero change case, we add a check to qd_check_sync so it puts the qd and slot references acquired in gfs2_quota_change and skip the unneeded sync. Signed-off-by: Bob Peterson Signed-off-by: Andreas Gruenbacher --- fs/gfs2/quota.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 171b2713d2e5e..41d0232532a03 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -457,6 +457,17 @@ static int qd_check_sync(struct gfs2_sbd *sdp, struct gfs2_quota_data *qd, (sync_gen && (qd->qd_sync_gen >= *sync_gen))) return 0; + /* + * If qd_change is 0 it means a pending quota change was negated. + * We should not sync it, but we still have a qd reference and slot + * reference taken by gfs2_quota_change -> do_qc that need to be put. + */ + if (!qd->qd_change && test_and_clear_bit(QDF_CHANGE, &qd->qd_flags)) { + slot_put(qd); + qd_put(qd); + return 0; + } + if (!lockref_get_not_dead(&qd->qd_lockref)) return 0; -- GitLab From 0abd1557e21c617bd13fc18f7725fc6363c05913 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 2 Oct 2023 03:33:44 +0100 Subject: [PATCH 0403/1451] gfs2: fix an oops in gfs2_permission In RCU mode, we might race with gfs2_evict_inode(), which zeroes ->i_gl. Freeing of the object it points to is RCU-delayed, so if we manage to fetch the pointer before it's been replaced with NULL, we are fine. Check if we'd fetched NULL and treat that as "bail out and tell the caller to get out of RCU mode". Signed-off-by: Al Viro Signed-off-by: Andreas Gruenbacher --- fs/gfs2/inode.c | 11 +++++++++-- fs/gfs2/super.c | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 2880d6ca19e10..697f95047033d 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1868,14 +1868,21 @@ int gfs2_permission(struct mnt_idmap *idmap, struct inode *inode, { struct gfs2_inode *ip; struct gfs2_holder i_gh; + struct gfs2_glock *gl; int error; gfs2_holder_mark_uninitialized(&i_gh); ip = GFS2_I(inode); - if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { + gl = rcu_dereference(ip->i_gl); + if (unlikely(!gl)) { + /* inode is getting torn down, must be RCU mode */ + WARN_ON_ONCE(!(mask & MAY_NOT_BLOCK)); + return -ECHILD; + } + if (gfs2_glock_is_locked_by_me(gl) == NULL) { if (mask & MAY_NOT_BLOCK) return -ECHILD; - error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); + error = gfs2_glock_nq_init(gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); if (error) return error; } diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 3141db77189e9..dd2720a5ca62f 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1540,7 +1540,7 @@ static void gfs2_evict_inode(struct inode *inode) wait_on_bit_io(&ip->i_flags, GIF_GLOP_PENDING, TASK_UNINTERRUPTIBLE); gfs2_glock_add_to_lru(ip->i_gl); gfs2_glock_put_eventually(ip->i_gl); - ip->i_gl = NULL; + rcu_assign_pointer(ip->i_gl, NULL); } } -- GitLab From 0f6a90436a5771fc9f6ca0d1e64f7549219e6c3c Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 3 Oct 2023 13:52:36 -0300 Subject: [PATCH 0404/1451] iommu: Do not use IOMMU_DOMAIN_DMA if CONFIG_IOMMU_DMA is not enabled msm_iommu platforms do not select either CONFIG_IOMMU_DMA or CONFIG_ARM_DMA_USE_IOMMU so they create a IOMMU_DOMAIN_DMA domain by default and never populate it. This acts like a BLOCKED domain and breaks the GPU driver on the platform. Detect this and force use of IDENTITY instead. Fixes: 98ac73f99bc4 ("iommu: Require a default_domain for all iommu drivers") Reported-by: Dmitry Baryshkov Link: https://lore.kernel.org/linux-iommu/CAA8EJprz7VVmBG68U9zLuqPd0UdSRHYoLDJSP6tCj6H6qanuTQ@mail.gmail.com/ Signed-off-by: Jason Gunthorpe Reviewed-by: Jerry Snitselaar Tested-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/0-v1-20700abdf239+19c-iommu_no_dma_iommu_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 1ecac2b5c54f4..21d45e6a5931a 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1920,6 +1920,18 @@ static int iommu_get_default_domain_type(struct iommu_group *group, } } + /* + * If the common dma ops are not selected in kconfig then we cannot use + * IOMMU_DOMAIN_DMA at all. Force IDENTITY if nothing else has been + * selected. + */ + if (!IS_ENABLED(CONFIG_IOMMU_DMA)) { + if (WARN_ON(driver_type == IOMMU_DOMAIN_DMA)) + return -1; + if (!driver_type) + driver_type = IOMMU_DOMAIN_IDENTITY; + } + if (untrusted) { if (driver_type && driver_type != IOMMU_DOMAIN_DMA) { dev_err_ratelimited( -- GitLab From 92bce97f0c341d3037b0f364b6839483f6a41cae Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Wed, 4 Oct 2023 10:56:12 +0200 Subject: [PATCH 0405/1451] s390/pci: Fix reset of IOMMU software counters Together with enabling the Function Measurement Block zpci_fmb_enable_device() also resets the software counters. This allows to use "echo 0 > /sys/kernel/debug/pci//statistics" followed by echo "1 > /../statistics" to reset all counters. In commit c76c067e488c ("s390/pci: Use dma-iommu layer") this use of the now obsolete counters in struct zpci_device was missed as was their removal. Fix this by resetting the new counters and removing the old ones. Fixes: c76c067e488c ("s390/pci: Use dma-iommu layer") Signed-off-by: Niklas Schnelle Reviewed-by: Matthew Rosato Link: https://lore.kernel.org/r/20231004-dma_iommu_fix-v1-1-129777cd8232@linux.ibm.com Signed-off-by: Joerg Roedel --- arch/s390/include/asm/pci.h | 4 ---- arch/s390/pci/pci.c | 13 ++++++++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index 3f74f1cf37dfd..e91cd6bbc330d 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h @@ -173,10 +173,6 @@ struct zpci_dev { struct zpci_fmb *fmb; u16 fmb_update; /* update interval */ u16 fmb_length; - /* software counters */ - atomic64_t allocated_pages; - atomic64_t mapped_pages; - atomic64_t unmapped_pages; u8 version; enum pci_bus_speed max_bus_speed; diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index 563cb72d9ed0f..63fd9e1d9f22c 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -157,6 +157,7 @@ int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas) int zpci_fmb_enable_device(struct zpci_dev *zdev) { u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_SET_MEASURE); + struct zpci_iommu_ctrs *ctrs; struct zpci_fib fib = {0}; u8 cc, status; @@ -169,9 +170,15 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev) WARN_ON((u64) zdev->fmb & 0xf); /* reset software counters */ - atomic64_set(&zdev->allocated_pages, 0); - atomic64_set(&zdev->mapped_pages, 0); - atomic64_set(&zdev->unmapped_pages, 0); + ctrs = zpci_get_iommu_ctrs(zdev); + if (ctrs) { + atomic64_set(&ctrs->mapped_pages, 0); + atomic64_set(&ctrs->unmapped_pages, 0); + atomic64_set(&ctrs->global_rpcits, 0); + atomic64_set(&ctrs->sync_map_rpcits, 0); + atomic64_set(&ctrs->sync_rpcits, 0); + } + fib.fmb_addr = virt_to_phys(zdev->fmb); fib.gd = zdev->gisa; -- GitLab From b85b4f30846bb169c114e99ceee17cc119f02a4b Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 4 Oct 2023 09:08:32 -0300 Subject: [PATCH 0406/1451] iommu: Fix return code in iommu_group_alloc_default_domain() This function returns NULL on errors, not ERR_PTR. Fixes: 1c68cbc64fe6 ("iommu: Add IOMMU_DOMAIN_PLATFORM") Reported-by: Dan Carpenter Link: https://lore.kernel.org/r/8fb75157-6c81-4a9c-9992-d73d49902fa8@moroto.mountain Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/0-v2-ee2bae9af0f2+96-iommu_ga_err_ptr_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 21d45e6a5931a..f9f315d58a3a1 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1787,7 +1787,7 @@ iommu_group_alloc_default_domain(struct iommu_group *group, int req_type) */ if (ops->default_domain) { if (req_type) - return ERR_PTR(-EINVAL); + return NULL; return ops->default_domain; } -- GitLab From 595b2c5917d89f5aeeecb4c74e29c0ecfabdc7e9 Mon Sep 17 00:00:00 2001 From: Keguang Zhang Date: Wed, 30 Aug 2023 21:35:05 +0800 Subject: [PATCH 0407/1451] MIPS: loongson32: Remove dma.h and nand.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 7b3415f581c7 ("MIPS: Loongson32: Remove unused platform devices"), struct plat_ls1x_dma and plat_ls1x_nand are unused. Then, dma.h and nand.h are useless. Therefore, remove these useless header files. Signed-off-by: Keguang Zhang Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/mach-loongson32/dma.h | 21 --------------- arch/mips/include/asm/mach-loongson32/nand.h | 26 ------------------- .../include/asm/mach-loongson32/platform.h | 3 --- arch/mips/loongson32/common/platform.c | 2 -- arch/mips/loongson32/ls1b/board.c | 2 -- 5 files changed, 54 deletions(-) delete mode 100644 arch/mips/include/asm/mach-loongson32/dma.h delete mode 100644 arch/mips/include/asm/mach-loongson32/nand.h diff --git a/arch/mips/include/asm/mach-loongson32/dma.h b/arch/mips/include/asm/mach-loongson32/dma.h deleted file mode 100644 index e917b3ccb2c2d..0000000000000 --- a/arch/mips/include/asm/mach-loongson32/dma.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (c) 2015 Zhang, Keguang - * - * Loongson 1 NAND platform support. - */ - -#ifndef __ASM_MACH_LOONGSON32_DMA_H -#define __ASM_MACH_LOONGSON32_DMA_H - -#define LS1X_DMA_CHANNEL0 0 -#define LS1X_DMA_CHANNEL1 1 -#define LS1X_DMA_CHANNEL2 2 - -struct plat_ls1x_dma { - int nr_channels; -}; - -extern struct plat_ls1x_dma ls1b_dma_pdata; - -#endif /* __ASM_MACH_LOONGSON32_DMA_H */ diff --git a/arch/mips/include/asm/mach-loongson32/nand.h b/arch/mips/include/asm/mach-loongson32/nand.h deleted file mode 100644 index aaf5ed19d78d4..0000000000000 --- a/arch/mips/include/asm/mach-loongson32/nand.h +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (c) 2015 Zhang, Keguang - * - * Loongson 1 NAND platform support. - */ - -#ifndef __ASM_MACH_LOONGSON32_NAND_H -#define __ASM_MACH_LOONGSON32_NAND_H - -#include -#include - -struct plat_ls1x_nand { - struct mtd_partition *parts; - unsigned int nr_parts; - - int hold_cycle; - int wait_cycle; -}; - -extern struct plat_ls1x_nand ls1b_nand_pdata; - -bool ls1x_dma_filter_fn(struct dma_chan *chan, void *param); - -#endif /* __ASM_MACH_LOONGSON32_NAND_H */ diff --git a/arch/mips/include/asm/mach-loongson32/platform.h b/arch/mips/include/asm/mach-loongson32/platform.h index 2cdcfb5f6012d..f74292b13bc3b 100644 --- a/arch/mips/include/asm/mach-loongson32/platform.h +++ b/arch/mips/include/asm/mach-loongson32/platform.h @@ -8,9 +8,6 @@ #include -#include -#include - extern struct platform_device ls1x_uart_pdev; extern struct platform_device ls1x_eth0_pdev; extern struct platform_device ls1x_eth1_pdev; diff --git a/arch/mips/loongson32/common/platform.c b/arch/mips/loongson32/common/platform.c index 8075590a9f834..623eb4bc7b41e 100644 --- a/arch/mips/loongson32/common/platform.c +++ b/arch/mips/loongson32/common/platform.c @@ -15,8 +15,6 @@ #include #include -#include -#include /* 8250/16550 compatible UART */ #define LS1X_UART(_id) \ diff --git a/arch/mips/loongson32/ls1b/board.c b/arch/mips/loongson32/ls1b/board.c index fed8d432ef206..fe115bdcb22ce 100644 --- a/arch/mips/loongson32/ls1b/board.c +++ b/arch/mips/loongson32/ls1b/board.c @@ -8,8 +8,6 @@ #include #include -#include -#include #include static const struct gpio_led ls1x_gpio_leds[] __initconst = { -- GitLab From 04318868abaa82f7c6e9e0ce323aa5460b7fc9da Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 30 Aug 2023 17:11:55 +0200 Subject: [PATCH 0408/1451] mips: dts: ingenic: Remove unneeded probe-type properties The "probe-type" property was only needed when used with the (long obsolete) "direct-mapped" compatible value. Signed-off-by: Geert Uytterhoeven Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/ingenic/jz4725b.dtsi | 1 - arch/mips/boot/dts/ingenic/jz4770.dtsi | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/mips/boot/dts/ingenic/jz4725b.dtsi b/arch/mips/boot/dts/ingenic/jz4725b.dtsi index acbbe8c4664c1..c5c5a094c37d2 100644 --- a/arch/mips/boot/dts/ingenic/jz4725b.dtsi +++ b/arch/mips/boot/dts/ingenic/jz4725b.dtsi @@ -366,7 +366,6 @@ bch: ecc-controller@130d0000 { rom: memory@1fc00000 { compatible = "mtd-rom"; - probe-type = "map_rom"; reg = <0x1fc00000 0x2000>; bank-width = <4>; diff --git a/arch/mips/boot/dts/ingenic/jz4770.dtsi b/arch/mips/boot/dts/ingenic/jz4770.dtsi index 9c0099919db7a..504e895e916e5 100644 --- a/arch/mips/boot/dts/ingenic/jz4770.dtsi +++ b/arch/mips/boot/dts/ingenic/jz4770.dtsi @@ -461,7 +461,6 @@ usb_otg: usb@13440000 { rom: memory@1fc00000 { compatible = "mtd-rom"; - probe-type = "map_rom"; reg = <0x1fc00000 0x2000>; bank-width = <4>; -- GitLab From b44ae980e9d026c41101d97cf96c0eb09d490b35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Sun, 17 Sep 2023 13:37:53 +0300 Subject: [PATCH 0409/1451] mips: dts: ralink: mt7621: define each reset as an item MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each item of the resets property should define a reset. Split the item with two resets on the ethernet node into two separate items. Sort the items of the clocks property to the same line as a trivial change. Signed-off-by: Arınç ÜNAL Acked-by: Sergio Paracuellos Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/ralink/mt7621.dtsi | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/mips/boot/dts/ralink/mt7621.dtsi b/arch/mips/boot/dts/ralink/mt7621.dtsi index 7caed0d14f11a..35a10258f2357 100644 --- a/arch/mips/boot/dts/ralink/mt7621.dtsi +++ b/arch/mips/boot/dts/ralink/mt7621.dtsi @@ -300,14 +300,13 @@ ethernet: ethernet@1e100000 { compatible = "mediatek,mt7621-eth"; reg = <0x1e100000 0x10000>; - clocks = <&sysc MT7621_CLK_FE>, - <&sysc MT7621_CLK_ETH>; + clocks = <&sysc MT7621_CLK_FE>, <&sysc MT7621_CLK_ETH>; clock-names = "fe", "ethif"; #address-cells = <1>; #size-cells = <0>; - resets = <&sysc MT7621_RST_FE &sysc MT7621_RST_ETH>; + resets = <&sysc MT7621_RST_FE>, <&sysc MT7621_RST_ETH>; reset-names = "fe", "eth"; interrupt-parent = <&gic>; -- GitLab From 70f8cd94f2bc7da7577f7751d03e568006accb97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= Date: Mon, 18 Sep 2023 10:59:15 +0300 Subject: [PATCH 0410/1451] mips: dts: ralink: mt7621: rename to GnuBee GB-PC1 and GnuBee GB-PC2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename GB-PC1 to GnuBee GB-PC1, and GB-PC2 to GnuBee GB-PC2 to include brand and model name. Signed-off-by: Arınç ÜNAL Acked-by: Sergio Paracuellos Signed-off-by: Thomas Bogendoerfer --- arch/mips/boot/dts/ralink/mt7621-gnubee-gb-pc1.dts | 2 +- arch/mips/boot/dts/ralink/mt7621-gnubee-gb-pc2.dts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/boot/dts/ralink/mt7621-gnubee-gb-pc1.dts b/arch/mips/boot/dts/ralink/mt7621-gnubee-gb-pc1.dts index 129b6710b699d..f9c262cc2e96b 100644 --- a/arch/mips/boot/dts/ralink/mt7621-gnubee-gb-pc1.dts +++ b/arch/mips/boot/dts/ralink/mt7621-gnubee-gb-pc1.dts @@ -8,7 +8,7 @@ / { compatible = "gnubee,gb-pc1", "mediatek,mt7621-soc"; - model = "GB-PC1"; + model = "GnuBee GB-PC1"; memory@0 { device_type = "memory"; diff --git a/arch/mips/boot/dts/ralink/mt7621-gnubee-gb-pc2.dts b/arch/mips/boot/dts/ralink/mt7621-gnubee-gb-pc2.dts index f810cd10f4f4f..b281e13f22ed2 100644 --- a/arch/mips/boot/dts/ralink/mt7621-gnubee-gb-pc2.dts +++ b/arch/mips/boot/dts/ralink/mt7621-gnubee-gb-pc2.dts @@ -8,7 +8,7 @@ / { compatible = "gnubee,gb-pc2", "mediatek,mt7621-soc"; - model = "GB-PC2"; + model = "GnuBee GB-PC2"; memory@0 { device_type = "memory"; -- GitLab From 4d0f332a6fb65aac2fa98e61bbed4ac9dfcf0a01 Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Tue, 19 Sep 2023 19:05:01 +0800 Subject: [PATCH 0411/1451] MIPS: Remove dead code in relocate_new_kernel There are two adjacent "b" instructions, the second one is unreachable, it is dead code, just remove it. Signed-off-by: Tiezhu Yang Signed-off-by: Thomas Bogendoerfer --- arch/mips/kernel/relocate_kernel.S | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/kernel/relocate_kernel.S b/arch/mips/kernel/relocate_kernel.S index f5b2ef979b437..8f0a7263a9d61 100644 --- a/arch/mips/kernel/relocate_kernel.S +++ b/arch/mips/kernel/relocate_kernel.S @@ -66,7 +66,6 @@ copy_word: LONG_ADDIU s6, s6, -1 beq s6, zero, process_entry b copy_word - b process_entry done: #ifdef CONFIG_SMP -- GitLab From 2992e07038aa38e1e156a833d6274bf330642722 Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Thu, 10 Aug 2023 15:42:57 +0800 Subject: [PATCH 0412/1451] pwm: atmel: Remove redundant of_match_ptr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver depends on CONFIG_OF, it is not necessary to use of_match_ptr() here. Signed-off-by: Ruan Jinjie Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 1f73325d1bea0..35ae876bf2ea2 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -547,7 +547,7 @@ static int atmel_pwm_probe(struct platform_device *pdev) static struct platform_driver atmel_pwm_driver = { .driver = { .name = "atmel-pwm", - .of_match_table = of_match_ptr(atmel_pwm_dt_ids), + .of_match_table = atmel_pwm_dt_ids, }, .probe = atmel_pwm_probe, }; -- GitLab From 7818f0bcc195e7c49eaaa031f0c26c59978469f6 Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Thu, 10 Aug 2023 15:42:58 +0800 Subject: [PATCH 0413/1451] pwm: omap-dmtimer: Remove redundant of_match_ptr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver depends on CONFIG_OF, it is not necessary to use of_match_ptr() here. Signed-off-by: Ruan Jinjie Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-omap-dmtimer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c index 4889fbd8a4311..94faa46506866 100644 --- a/drivers/pwm/pwm-omap-dmtimer.c +++ b/drivers/pwm/pwm-omap-dmtimer.c @@ -466,7 +466,7 @@ MODULE_DEVICE_TABLE(of, pwm_omap_dmtimer_of_match); static struct platform_driver pwm_omap_dmtimer_driver = { .driver = { .name = "omap-dmtimer-pwm", - .of_match_table = of_match_ptr(pwm_omap_dmtimer_of_match), + .of_match_table = pwm_omap_dmtimer_of_match, }, .probe = pwm_omap_dmtimer_probe, .remove_new = pwm_omap_dmtimer_remove, -- GitLab From c3c653422a265a3b5dfdf8567eebd5116311c36d Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 22 Sep 2023 09:42:27 -0300 Subject: [PATCH 0414/1451] dt-bindings: pwm: mxs: Document fsl,imx28-pwm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit imx28 uses the same PWM block that is found on imx23. Add an entry for fsl,imx28-pwm. Signed-off-by: Fabio Estevam Acked-by: Uwe Kleine-König Acked-by: Rob Herring Signed-off-by: Thierry Reding --- Documentation/devicetree/bindings/pwm/mxs-pwm.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/pwm/mxs-pwm.yaml b/Documentation/devicetree/bindings/pwm/mxs-pwm.yaml index 6ffbed204c259..655f008081d55 100644 --- a/Documentation/devicetree/bindings/pwm/mxs-pwm.yaml +++ b/Documentation/devicetree/bindings/pwm/mxs-pwm.yaml @@ -15,8 +15,12 @@ allOf: properties: compatible: - enum: - - fsl,imx23-pwm + oneOf: + - const: fsl,imx23-pwm + - items: + - enum: + - fsl,imx28-pwm + - const: fsl,imx23-pwm reg: maxItems: 1 -- GitLab From 42b9116ce12579692ec18ad9446ea5ad832ea0ef Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 22 Sep 2023 09:42:28 -0300 Subject: [PATCH 0415/1451] dt-bindings: pwm: mxs: Document the clocks property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'clocks' property is mandatory for the PWM to operate. Document it. Signed-off-by: Fabio Estevam Reviewed-by: Uwe Kleine-König Acked-by: Conor Dooley Signed-off-by: Thierry Reding --- Documentation/devicetree/bindings/pwm/mxs-pwm.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/pwm/mxs-pwm.yaml b/Documentation/devicetree/bindings/pwm/mxs-pwm.yaml index 655f008081d55..8f50e23ca8c9b 100644 --- a/Documentation/devicetree/bindings/pwm/mxs-pwm.yaml +++ b/Documentation/devicetree/bindings/pwm/mxs-pwm.yaml @@ -25,6 +25,9 @@ properties: reg: maxItems: 1 + clocks: + maxItems: 1 + "#pwm-cells": const: 3 @@ -35,6 +38,7 @@ properties: required: - compatible - reg + - clocks - fsl,pwm-number additionalProperties: false @@ -44,6 +48,7 @@ examples: pwm@80064000 { compatible = "fsl,imx23-pwm"; reg = <0x80064000 0x2000>; + clocks = <&clks 30>; #pwm-cells = <3>; fsl,pwm-number = <8>; }; -- GitLab From 162844744fa51edbe0d0857c493e37af336af666 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Mon, 18 Sep 2023 11:23:27 +0100 Subject: [PATCH 0416/1451] pwm: microchip-core: Convert SOC_MICROCHIP_POLARFIRE to ARCH_MICROCHIP_POLARFIRE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As part of converting RISC-V SOC_FOO symbols to ARCH_FOO to match the use of such symbols on other architectures, convert the Microchip FPGA PWM driver to use the new symbol. Signed-off-by: Conor Dooley Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 8ebcddf91f7b7..502d041d4a11e 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -407,7 +407,7 @@ config PWM_MEDIATEK config PWM_MICROCHIP_CORE tristate "Microchip corePWM PWM support" - depends on SOC_MICROCHIP_POLARFIRE || COMPILE_TEST + depends on ARCH_MICROCHIP_POLARFIRE || COMPILE_TEST depends on HAS_IOMEM && OF help PWM driver for Microchip FPGA soft IP core. -- GitLab From 5a0b11a180a9b82b4437a4be1cf73530053f139b Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Fri, 6 Oct 2023 09:57:02 +0000 Subject: [PATCH 0417/1451] iommu/amd: Remove iommu_v2 module AMD GPU driver which was the only in-kernel user of iommu_v2 module removed dependency on iommu_v2 module. Also we are working on adding SVA support in AMD IOMMU driver. Device drivers are expected to use common SVA framework to enable device PASID/PRI features. Removing iommu_v2 module and then adding SVA simplifies the development. Hence remove iommu_v2 module. Cc: Alex Deucher Cc: Joerg Roedel Cc: Felix Kuehling Signed-off-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Reviewed-by: Jerry Snitselaar Tested-by: Alex Deucher Link: https://lore.kernel.org/r/20231006095706.5694-2-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/Kconfig | 9 - drivers/iommu/amd/Makefile | 1 - drivers/iommu/amd/amd_iommu.h | 5 - drivers/iommu/amd/iommu.c | 40 -- drivers/iommu/amd/iommu_v2.c | 996 ---------------------------------- include/linux/amd-iommu.h | 94 ---- 6 files changed, 1145 deletions(-) delete mode 100644 drivers/iommu/amd/iommu_v2.c diff --git a/drivers/iommu/amd/Kconfig b/drivers/iommu/amd/Kconfig index 9b5fc3356bf2d..75132ae861a22 100644 --- a/drivers/iommu/amd/Kconfig +++ b/drivers/iommu/amd/Kconfig @@ -22,15 +22,6 @@ config AMD_IOMMU your BIOS for an option to enable it or if you have an IVRS ACPI table. -config AMD_IOMMU_V2 - tristate "AMD IOMMU Version 2 driver" - depends on AMD_IOMMU - select MMU_NOTIFIER - help - This option enables support for the AMD IOMMUv2 features of the IOMMU - hardware. Select this option if you want to use devices that support - the PCI PRI and PASID interface. - config AMD_IOMMU_DEBUGFS bool "Enable AMD IOMMU internals in DebugFS" depends on AMD_IOMMU && IOMMU_DEBUGFS diff --git a/drivers/iommu/amd/Makefile b/drivers/iommu/amd/Makefile index 773d8aa002837..f454fbb1569eb 100644 --- a/drivers/iommu/amd/Makefile +++ b/drivers/iommu/amd/Makefile @@ -1,4 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_AMD_IOMMU) += iommu.o init.o quirks.o io_pgtable.o io_pgtable_v2.o obj-$(CONFIG_AMD_IOMMU_DEBUGFS) += debugfs.o -obj-$(CONFIG_AMD_IOMMU_V2) += iommu_v2.o diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h index 9df53961d5ef1..5b8a1e2dd3d03 100644 --- a/drivers/iommu/amd/amd_iommu.h +++ b/drivers/iommu/amd/amd_iommu.h @@ -38,9 +38,6 @@ extern int amd_iommu_guest_ir; extern enum io_pgtable_fmt amd_iommu_pgtable; extern int amd_iommu_gpt_level; -/* IOMMUv2 specific functions */ -struct iommu_domain; - bool amd_iommu_v2_supported(void); struct amd_iommu *get_amd_iommu(unsigned int idx); u8 amd_iommu_pc_get_max_banks(unsigned int idx); @@ -57,8 +54,6 @@ void amd_iommu_pdev_disable_cap_pri(struct pci_dev *pdev); int amd_iommu_register_ppr_notifier(struct notifier_block *nb); int amd_iommu_unregister_ppr_notifier(struct notifier_block *nb); -void amd_iommu_domain_direct_map(struct iommu_domain *dom); -int amd_iommu_domain_enable_v2(struct iommu_domain *dom, int pasids); int amd_iommu_flush_page(struct iommu_domain *dom, u32 pasid, u64 address); void amd_iommu_update_and_flush_device_table(struct protection_domain *domain); void amd_iommu_domain_update(struct protection_domain *domain); diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index f3448a2b6c0ee..fd0d7b2f30dce 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -2568,46 +2568,6 @@ int amd_iommu_unregister_ppr_notifier(struct notifier_block *nb) } EXPORT_SYMBOL(amd_iommu_unregister_ppr_notifier); -void amd_iommu_domain_direct_map(struct iommu_domain *dom) -{ - struct protection_domain *domain = to_pdomain(dom); - unsigned long flags; - - spin_lock_irqsave(&domain->lock, flags); - - if (domain->iop.pgtbl_cfg.tlb) - free_io_pgtable_ops(&domain->iop.iop.ops); - - spin_unlock_irqrestore(&domain->lock, flags); -} -EXPORT_SYMBOL(amd_iommu_domain_direct_map); - -int amd_iommu_domain_enable_v2(struct iommu_domain *dom, int pasids) -{ - struct protection_domain *pdom = to_pdomain(dom); - unsigned long flags; - int ret; - - spin_lock_irqsave(&pdom->lock, flags); - - /* - * Save us all sanity checks whether devices already in the - * domain support IOMMUv2. Just force that the domain has no - * devices attached when it is switched into IOMMUv2 mode. - */ - ret = -EBUSY; - if (pdom->dev_cnt > 0 || pdom->flags & PD_IOMMUV2_MASK) - goto out; - - if (!pdom->gcr3_tbl) - ret = setup_gcr3_table(pdom, pasids); - -out: - spin_unlock_irqrestore(&pdom->lock, flags); - return ret; -} -EXPORT_SYMBOL(amd_iommu_domain_enable_v2); - static int __flush_pasid(struct protection_domain *domain, u32 pasid, u64 address, bool size) { diff --git a/drivers/iommu/amd/iommu_v2.c b/drivers/iommu/amd/iommu_v2.c deleted file mode 100644 index 57c2fb1146e25..0000000000000 --- a/drivers/iommu/amd/iommu_v2.c +++ /dev/null @@ -1,996 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2010-2012 Advanced Micro Devices, Inc. - * Author: Joerg Roedel - */ - -#define pr_fmt(fmt) "AMD-Vi: " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "amd_iommu.h" - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Joerg Roedel "); - -#define PRI_QUEUE_SIZE 512 - -struct pri_queue { - atomic_t inflight; - bool finish; - int status; -}; - -struct pasid_state { - struct list_head list; /* For global state-list */ - refcount_t count; /* Reference count */ - unsigned mmu_notifier_count; /* Counting nested mmu_notifier - calls */ - struct mm_struct *mm; /* mm_struct for the faults */ - struct mmu_notifier mn; /* mmu_notifier handle */ - struct pri_queue pri[PRI_QUEUE_SIZE]; /* PRI tag states */ - struct device_state *device_state; /* Link to our device_state */ - u32 pasid; /* PASID index */ - bool invalid; /* Used during setup and - teardown of the pasid */ - spinlock_t lock; /* Protect pri_queues and - mmu_notifer_count */ - wait_queue_head_t wq; /* To wait for count == 0 */ -}; - -struct device_state { - struct list_head list; - u32 sbdf; - atomic_t count; - struct pci_dev *pdev; - struct pasid_state **states; - struct iommu_domain *domain; - int pasid_levels; - int max_pasids; - amd_iommu_invalid_ppr_cb inv_ppr_cb; - amd_iommu_invalidate_ctx inv_ctx_cb; - spinlock_t lock; - wait_queue_head_t wq; -}; - -struct fault { - struct work_struct work; - struct device_state *dev_state; - struct pasid_state *state; - struct mm_struct *mm; - u64 address; - u32 pasid; - u16 tag; - u16 finish; - u16 flags; -}; - -static LIST_HEAD(state_list); -static DEFINE_SPINLOCK(state_lock); - -static struct workqueue_struct *iommu_wq; - -static void free_pasid_states(struct device_state *dev_state); - -static struct device_state *__get_device_state(u32 sbdf) -{ - struct device_state *dev_state; - - list_for_each_entry(dev_state, &state_list, list) { - if (dev_state->sbdf == sbdf) - return dev_state; - } - - return NULL; -} - -static struct device_state *get_device_state(u32 sbdf) -{ - struct device_state *dev_state; - unsigned long flags; - - spin_lock_irqsave(&state_lock, flags); - dev_state = __get_device_state(sbdf); - if (dev_state != NULL) - atomic_inc(&dev_state->count); - spin_unlock_irqrestore(&state_lock, flags); - - return dev_state; -} - -static void free_device_state(struct device_state *dev_state) -{ - struct iommu_group *group; - - /* Get rid of any remaining pasid states */ - free_pasid_states(dev_state); - - /* - * Wait until the last reference is dropped before freeing - * the device state. - */ - wait_event(dev_state->wq, !atomic_read(&dev_state->count)); - - /* - * First detach device from domain - No more PRI requests will arrive - * from that device after it is unbound from the IOMMUv2 domain. - */ - group = iommu_group_get(&dev_state->pdev->dev); - if (WARN_ON(!group)) - return; - - iommu_detach_group(dev_state->domain, group); - - iommu_group_put(group); - - /* Everything is down now, free the IOMMUv2 domain */ - iommu_domain_free(dev_state->domain); - - /* Finally get rid of the device-state */ - kfree(dev_state); -} - -static void put_device_state(struct device_state *dev_state) -{ - if (atomic_dec_and_test(&dev_state->count)) - wake_up(&dev_state->wq); -} - -/* Must be called under dev_state->lock */ -static struct pasid_state **__get_pasid_state_ptr(struct device_state *dev_state, - u32 pasid, bool alloc) -{ - struct pasid_state **root, **ptr; - int level, index; - - level = dev_state->pasid_levels; - root = dev_state->states; - - while (true) { - - index = (pasid >> (9 * level)) & 0x1ff; - ptr = &root[index]; - - if (level == 0) - break; - - if (*ptr == NULL) { - if (!alloc) - return NULL; - - *ptr = (void *)get_zeroed_page(GFP_ATOMIC); - if (*ptr == NULL) - return NULL; - } - - root = (struct pasid_state **)*ptr; - level -= 1; - } - - return ptr; -} - -static int set_pasid_state(struct device_state *dev_state, - struct pasid_state *pasid_state, - u32 pasid) -{ - struct pasid_state **ptr; - unsigned long flags; - int ret; - - spin_lock_irqsave(&dev_state->lock, flags); - ptr = __get_pasid_state_ptr(dev_state, pasid, true); - - ret = -ENOMEM; - if (ptr == NULL) - goto out_unlock; - - ret = -ENOMEM; - if (*ptr != NULL) - goto out_unlock; - - *ptr = pasid_state; - - ret = 0; - -out_unlock: - spin_unlock_irqrestore(&dev_state->lock, flags); - - return ret; -} - -static void clear_pasid_state(struct device_state *dev_state, u32 pasid) -{ - struct pasid_state **ptr; - unsigned long flags; - - spin_lock_irqsave(&dev_state->lock, flags); - ptr = __get_pasid_state_ptr(dev_state, pasid, true); - - if (ptr == NULL) - goto out_unlock; - - *ptr = NULL; - -out_unlock: - spin_unlock_irqrestore(&dev_state->lock, flags); -} - -static struct pasid_state *get_pasid_state(struct device_state *dev_state, - u32 pasid) -{ - struct pasid_state **ptr, *ret = NULL; - unsigned long flags; - - spin_lock_irqsave(&dev_state->lock, flags); - ptr = __get_pasid_state_ptr(dev_state, pasid, false); - - if (ptr == NULL) - goto out_unlock; - - ret = *ptr; - if (ret) - refcount_inc(&ret->count); - -out_unlock: - spin_unlock_irqrestore(&dev_state->lock, flags); - - return ret; -} - -static void free_pasid_state(struct pasid_state *pasid_state) -{ - kfree(pasid_state); -} - -static void put_pasid_state(struct pasid_state *pasid_state) -{ - if (refcount_dec_and_test(&pasid_state->count)) - wake_up(&pasid_state->wq); -} - -static void put_pasid_state_wait(struct pasid_state *pasid_state) -{ - if (!refcount_dec_and_test(&pasid_state->count)) - wait_event(pasid_state->wq, !refcount_read(&pasid_state->count)); - free_pasid_state(pasid_state); -} - -static void unbind_pasid(struct pasid_state *pasid_state) -{ - struct iommu_domain *domain; - - domain = pasid_state->device_state->domain; - - /* - * Mark pasid_state as invalid, no more faults will we added to the - * work queue after this is visible everywhere. - */ - pasid_state->invalid = true; - - /* Make sure this is visible */ - smp_wmb(); - - /* After this the device/pasid can't access the mm anymore */ - amd_iommu_domain_clear_gcr3(domain, pasid_state->pasid); - - /* Make sure no more pending faults are in the queue */ - flush_workqueue(iommu_wq); -} - -static void free_pasid_states_level1(struct pasid_state **tbl) -{ - int i; - - for (i = 0; i < 512; ++i) { - if (tbl[i] == NULL) - continue; - - free_page((unsigned long)tbl[i]); - } -} - -static void free_pasid_states_level2(struct pasid_state **tbl) -{ - struct pasid_state **ptr; - int i; - - for (i = 0; i < 512; ++i) { - if (tbl[i] == NULL) - continue; - - ptr = (struct pasid_state **)tbl[i]; - free_pasid_states_level1(ptr); - } -} - -static void free_pasid_states(struct device_state *dev_state) -{ - struct pasid_state *pasid_state; - int i; - - for (i = 0; i < dev_state->max_pasids; ++i) { - pasid_state = get_pasid_state(dev_state, i); - if (pasid_state == NULL) - continue; - - put_pasid_state(pasid_state); - - /* Clear the pasid state so that the pasid can be re-used */ - clear_pasid_state(dev_state, pasid_state->pasid); - - /* - * This will call the mn_release function and - * unbind the PASID - */ - mmu_notifier_unregister(&pasid_state->mn, pasid_state->mm); - - put_pasid_state_wait(pasid_state); /* Reference taken in - amd_iommu_bind_pasid */ - - /* Drop reference taken in amd_iommu_bind_pasid */ - put_device_state(dev_state); - } - - if (dev_state->pasid_levels == 2) - free_pasid_states_level2(dev_state->states); - else if (dev_state->pasid_levels == 1) - free_pasid_states_level1(dev_state->states); - else - BUG_ON(dev_state->pasid_levels != 0); - - free_page((unsigned long)dev_state->states); -} - -static struct pasid_state *mn_to_state(struct mmu_notifier *mn) -{ - return container_of(mn, struct pasid_state, mn); -} - -static void mn_arch_invalidate_secondary_tlbs(struct mmu_notifier *mn, - struct mm_struct *mm, - unsigned long start, unsigned long end) -{ - struct pasid_state *pasid_state; - struct device_state *dev_state; - - pasid_state = mn_to_state(mn); - dev_state = pasid_state->device_state; - - if ((start ^ (end - 1)) < PAGE_SIZE) - amd_iommu_flush_page(dev_state->domain, pasid_state->pasid, - start); - else - amd_iommu_flush_tlb(dev_state->domain, pasid_state->pasid); -} - -static void mn_release(struct mmu_notifier *mn, struct mm_struct *mm) -{ - struct pasid_state *pasid_state; - struct device_state *dev_state; - bool run_inv_ctx_cb; - - might_sleep(); - - pasid_state = mn_to_state(mn); - dev_state = pasid_state->device_state; - run_inv_ctx_cb = !pasid_state->invalid; - - if (run_inv_ctx_cb && dev_state->inv_ctx_cb) - dev_state->inv_ctx_cb(dev_state->pdev, pasid_state->pasid); - - unbind_pasid(pasid_state); -} - -static const struct mmu_notifier_ops iommu_mn = { - .release = mn_release, - .arch_invalidate_secondary_tlbs = mn_arch_invalidate_secondary_tlbs, -}; - -static void set_pri_tag_status(struct pasid_state *pasid_state, - u16 tag, int status) -{ - unsigned long flags; - - spin_lock_irqsave(&pasid_state->lock, flags); - pasid_state->pri[tag].status = status; - spin_unlock_irqrestore(&pasid_state->lock, flags); -} - -static void finish_pri_tag(struct device_state *dev_state, - struct pasid_state *pasid_state, - u16 tag) -{ - unsigned long flags; - - spin_lock_irqsave(&pasid_state->lock, flags); - if (atomic_dec_and_test(&pasid_state->pri[tag].inflight) && - pasid_state->pri[tag].finish) { - amd_iommu_complete_ppr(dev_state->pdev, pasid_state->pasid, - pasid_state->pri[tag].status, tag); - pasid_state->pri[tag].finish = false; - pasid_state->pri[tag].status = PPR_SUCCESS; - } - spin_unlock_irqrestore(&pasid_state->lock, flags); -} - -static void handle_fault_error(struct fault *fault) -{ - int status; - - if (!fault->dev_state->inv_ppr_cb) { - set_pri_tag_status(fault->state, fault->tag, PPR_INVALID); - return; - } - - status = fault->dev_state->inv_ppr_cb(fault->dev_state->pdev, - fault->pasid, - fault->address, - fault->flags); - switch (status) { - case AMD_IOMMU_INV_PRI_RSP_SUCCESS: - set_pri_tag_status(fault->state, fault->tag, PPR_SUCCESS); - break; - case AMD_IOMMU_INV_PRI_RSP_INVALID: - set_pri_tag_status(fault->state, fault->tag, PPR_INVALID); - break; - case AMD_IOMMU_INV_PRI_RSP_FAIL: - set_pri_tag_status(fault->state, fault->tag, PPR_FAILURE); - break; - default: - BUG(); - } -} - -static bool access_error(struct vm_area_struct *vma, struct fault *fault) -{ - unsigned long requested = 0; - - if (fault->flags & PPR_FAULT_EXEC) - requested |= VM_EXEC; - - if (fault->flags & PPR_FAULT_READ) - requested |= VM_READ; - - if (fault->flags & PPR_FAULT_WRITE) - requested |= VM_WRITE; - - return (requested & ~vma->vm_flags) != 0; -} - -static void do_fault(struct work_struct *work) -{ - struct fault *fault = container_of(work, struct fault, work); - struct vm_area_struct *vma; - vm_fault_t ret = VM_FAULT_ERROR; - unsigned int flags = 0; - struct mm_struct *mm; - u64 address; - - mm = fault->state->mm; - address = fault->address; - - if (fault->flags & PPR_FAULT_USER) - flags |= FAULT_FLAG_USER; - if (fault->flags & PPR_FAULT_WRITE) - flags |= FAULT_FLAG_WRITE; - flags |= FAULT_FLAG_REMOTE; - - mmap_read_lock(mm); - vma = vma_lookup(mm, address); - if (!vma) - /* failed to get a vma in the right range */ - goto out; - - /* Check if we have the right permissions on the vma */ - if (access_error(vma, fault)) - goto out; - - ret = handle_mm_fault(vma, address, flags, NULL); -out: - mmap_read_unlock(mm); - - if (ret & VM_FAULT_ERROR) - /* failed to service fault */ - handle_fault_error(fault); - - finish_pri_tag(fault->dev_state, fault->state, fault->tag); - - put_pasid_state(fault->state); - - kfree(fault); -} - -static int ppr_notifier(struct notifier_block *nb, unsigned long e, void *data) -{ - struct amd_iommu_fault *iommu_fault; - struct pasid_state *pasid_state; - struct device_state *dev_state; - struct pci_dev *pdev = NULL; - unsigned long flags; - struct fault *fault; - bool finish; - u16 tag, devid, seg_id; - int ret; - - iommu_fault = data; - tag = iommu_fault->tag & 0x1ff; - finish = (iommu_fault->tag >> 9) & 1; - - seg_id = PCI_SBDF_TO_SEGID(iommu_fault->sbdf); - devid = PCI_SBDF_TO_DEVID(iommu_fault->sbdf); - pdev = pci_get_domain_bus_and_slot(seg_id, PCI_BUS_NUM(devid), - devid & 0xff); - if (!pdev) - return -ENODEV; - - ret = NOTIFY_DONE; - - /* In kdump kernel pci dev is not initialized yet -> send INVALID */ - if (amd_iommu_is_attach_deferred(&pdev->dev)) { - amd_iommu_complete_ppr(pdev, iommu_fault->pasid, - PPR_INVALID, tag); - goto out; - } - - dev_state = get_device_state(iommu_fault->sbdf); - if (dev_state == NULL) - goto out; - - pasid_state = get_pasid_state(dev_state, iommu_fault->pasid); - if (pasid_state == NULL || pasid_state->invalid) { - /* We know the device but not the PASID -> send INVALID */ - amd_iommu_complete_ppr(dev_state->pdev, iommu_fault->pasid, - PPR_INVALID, tag); - goto out_drop_state; - } - - spin_lock_irqsave(&pasid_state->lock, flags); - atomic_inc(&pasid_state->pri[tag].inflight); - if (finish) - pasid_state->pri[tag].finish = true; - spin_unlock_irqrestore(&pasid_state->lock, flags); - - fault = kzalloc(sizeof(*fault), GFP_ATOMIC); - if (fault == NULL) { - /* We are OOM - send success and let the device re-fault */ - finish_pri_tag(dev_state, pasid_state, tag); - goto out_drop_state; - } - - fault->dev_state = dev_state; - fault->address = iommu_fault->address; - fault->state = pasid_state; - fault->tag = tag; - fault->finish = finish; - fault->pasid = iommu_fault->pasid; - fault->flags = iommu_fault->flags; - INIT_WORK(&fault->work, do_fault); - - queue_work(iommu_wq, &fault->work); - - ret = NOTIFY_OK; - -out_drop_state: - - if (ret != NOTIFY_OK && pasid_state) - put_pasid_state(pasid_state); - - put_device_state(dev_state); - -out: - pci_dev_put(pdev); - return ret; -} - -static struct notifier_block ppr_nb = { - .notifier_call = ppr_notifier, -}; - -int amd_iommu_bind_pasid(struct pci_dev *pdev, u32 pasid, - struct task_struct *task) -{ - struct pasid_state *pasid_state; - struct device_state *dev_state; - struct mm_struct *mm; - u32 sbdf; - int ret; - - might_sleep(); - - if (!amd_iommu_v2_supported()) - return -ENODEV; - - sbdf = get_pci_sbdf_id(pdev); - dev_state = get_device_state(sbdf); - - if (dev_state == NULL) - return -EINVAL; - - ret = -EINVAL; - if (pasid >= dev_state->max_pasids) - goto out; - - ret = -ENOMEM; - pasid_state = kzalloc(sizeof(*pasid_state), GFP_KERNEL); - if (pasid_state == NULL) - goto out; - - - refcount_set(&pasid_state->count, 1); - init_waitqueue_head(&pasid_state->wq); - spin_lock_init(&pasid_state->lock); - - mm = get_task_mm(task); - pasid_state->mm = mm; - pasid_state->device_state = dev_state; - pasid_state->pasid = pasid; - pasid_state->invalid = true; /* Mark as valid only if we are - done with setting up the pasid */ - pasid_state->mn.ops = &iommu_mn; - - if (pasid_state->mm == NULL) - goto out_free; - - ret = mmu_notifier_register(&pasid_state->mn, mm); - if (ret) - goto out_free; - - ret = set_pasid_state(dev_state, pasid_state, pasid); - if (ret) - goto out_unregister; - - ret = amd_iommu_domain_set_gcr3(dev_state->domain, pasid, - __pa(pasid_state->mm->pgd)); - if (ret) - goto out_clear_state; - - /* Now we are ready to handle faults */ - pasid_state->invalid = false; - - /* - * Drop the reference to the mm_struct here. We rely on the - * mmu_notifier release call-back to inform us when the mm - * is going away. - */ - mmput(mm); - - return 0; - -out_clear_state: - clear_pasid_state(dev_state, pasid); - -out_unregister: - mmu_notifier_unregister(&pasid_state->mn, mm); - mmput(mm); - -out_free: - free_pasid_state(pasid_state); - -out: - put_device_state(dev_state); - - return ret; -} -EXPORT_SYMBOL(amd_iommu_bind_pasid); - -void amd_iommu_unbind_pasid(struct pci_dev *pdev, u32 pasid) -{ - struct pasid_state *pasid_state; - struct device_state *dev_state; - u32 sbdf; - - might_sleep(); - - if (!amd_iommu_v2_supported()) - return; - - sbdf = get_pci_sbdf_id(pdev); - dev_state = get_device_state(sbdf); - if (dev_state == NULL) - return; - - if (pasid >= dev_state->max_pasids) - goto out; - - pasid_state = get_pasid_state(dev_state, pasid); - if (pasid_state == NULL) - goto out; - /* - * Drop reference taken here. We are safe because we still hold - * the reference taken in the amd_iommu_bind_pasid function. - */ - put_pasid_state(pasid_state); - - /* Clear the pasid state so that the pasid can be re-used */ - clear_pasid_state(dev_state, pasid_state->pasid); - - /* - * Call mmu_notifier_unregister to drop our reference - * to pasid_state->mm - */ - mmu_notifier_unregister(&pasid_state->mn, pasid_state->mm); - - put_pasid_state_wait(pasid_state); /* Reference taken in - amd_iommu_bind_pasid */ -out: - /* Drop reference taken in this function */ - put_device_state(dev_state); - - /* Drop reference taken in amd_iommu_bind_pasid */ - put_device_state(dev_state); -} -EXPORT_SYMBOL(amd_iommu_unbind_pasid); - -int amd_iommu_init_device(struct pci_dev *pdev, int pasids) -{ - struct device_state *dev_state; - struct iommu_group *group; - unsigned long flags; - int ret, tmp; - u32 sbdf; - - might_sleep(); - - /* - * When memory encryption is active the device is likely not in a - * direct-mapped domain. Forbid using IOMMUv2 functionality for now. - */ - if (cc_platform_has(CC_ATTR_MEM_ENCRYPT)) - return -ENODEV; - - if (!amd_iommu_v2_supported()) - return -ENODEV; - - if (pasids <= 0 || pasids > (PASID_MASK + 1)) - return -EINVAL; - - sbdf = get_pci_sbdf_id(pdev); - - dev_state = kzalloc(sizeof(*dev_state), GFP_KERNEL); - if (dev_state == NULL) - return -ENOMEM; - - spin_lock_init(&dev_state->lock); - init_waitqueue_head(&dev_state->wq); - dev_state->pdev = pdev; - dev_state->sbdf = sbdf; - - tmp = pasids; - for (dev_state->pasid_levels = 0; (tmp - 1) & ~0x1ff; tmp >>= 9) - dev_state->pasid_levels += 1; - - atomic_set(&dev_state->count, 1); - dev_state->max_pasids = pasids; - - ret = -ENOMEM; - dev_state->states = (void *)get_zeroed_page(GFP_KERNEL); - if (dev_state->states == NULL) - goto out_free_dev_state; - - dev_state->domain = iommu_domain_alloc(&pci_bus_type); - if (dev_state->domain == NULL) - goto out_free_states; - - /* See iommu_is_default_domain() */ - dev_state->domain->type = IOMMU_DOMAIN_IDENTITY; - amd_iommu_domain_direct_map(dev_state->domain); - - ret = amd_iommu_domain_enable_v2(dev_state->domain, pasids); - if (ret) - goto out_free_domain; - - group = iommu_group_get(&pdev->dev); - if (!group) { - ret = -EINVAL; - goto out_free_domain; - } - - ret = iommu_attach_group(dev_state->domain, group); - if (ret != 0) - goto out_drop_group; - - iommu_group_put(group); - - spin_lock_irqsave(&state_lock, flags); - - if (__get_device_state(sbdf) != NULL) { - spin_unlock_irqrestore(&state_lock, flags); - ret = -EBUSY; - goto out_free_domain; - } - - list_add_tail(&dev_state->list, &state_list); - - spin_unlock_irqrestore(&state_lock, flags); - - return 0; - -out_drop_group: - iommu_group_put(group); - -out_free_domain: - iommu_domain_free(dev_state->domain); - -out_free_states: - free_page((unsigned long)dev_state->states); - -out_free_dev_state: - kfree(dev_state); - - return ret; -} -EXPORT_SYMBOL(amd_iommu_init_device); - -void amd_iommu_free_device(struct pci_dev *pdev) -{ - struct device_state *dev_state; - unsigned long flags; - u32 sbdf; - - if (!amd_iommu_v2_supported()) - return; - - sbdf = get_pci_sbdf_id(pdev); - - spin_lock_irqsave(&state_lock, flags); - - dev_state = __get_device_state(sbdf); - if (dev_state == NULL) { - spin_unlock_irqrestore(&state_lock, flags); - return; - } - - list_del(&dev_state->list); - - spin_unlock_irqrestore(&state_lock, flags); - - put_device_state(dev_state); - free_device_state(dev_state); -} -EXPORT_SYMBOL(amd_iommu_free_device); - -int amd_iommu_set_invalid_ppr_cb(struct pci_dev *pdev, - amd_iommu_invalid_ppr_cb cb) -{ - struct device_state *dev_state; - unsigned long flags; - u32 sbdf; - int ret; - - if (!amd_iommu_v2_supported()) - return -ENODEV; - - sbdf = get_pci_sbdf_id(pdev); - - spin_lock_irqsave(&state_lock, flags); - - ret = -EINVAL; - dev_state = __get_device_state(sbdf); - if (dev_state == NULL) - goto out_unlock; - - dev_state->inv_ppr_cb = cb; - - ret = 0; - -out_unlock: - spin_unlock_irqrestore(&state_lock, flags); - - return ret; -} -EXPORT_SYMBOL(amd_iommu_set_invalid_ppr_cb); - -int amd_iommu_set_invalidate_ctx_cb(struct pci_dev *pdev, - amd_iommu_invalidate_ctx cb) -{ - struct device_state *dev_state; - unsigned long flags; - u32 sbdf; - int ret; - - if (!amd_iommu_v2_supported()) - return -ENODEV; - - sbdf = get_pci_sbdf_id(pdev); - - spin_lock_irqsave(&state_lock, flags); - - ret = -EINVAL; - dev_state = __get_device_state(sbdf); - if (dev_state == NULL) - goto out_unlock; - - dev_state->inv_ctx_cb = cb; - - ret = 0; - -out_unlock: - spin_unlock_irqrestore(&state_lock, flags); - - return ret; -} -EXPORT_SYMBOL(amd_iommu_set_invalidate_ctx_cb); - -static int __init amd_iommu_v2_init(void) -{ - int ret; - - if (!amd_iommu_v2_supported()) { - pr_info("AMD IOMMUv2 functionality not available on this system - This is not a bug.\n"); - /* - * Load anyway to provide the symbols to other modules - * which may use AMD IOMMUv2 optionally. - */ - return 0; - } - - ret = -ENOMEM; - iommu_wq = alloc_workqueue("amd_iommu_v2", WQ_MEM_RECLAIM, 0); - if (iommu_wq == NULL) - goto out; - - amd_iommu_register_ppr_notifier(&ppr_nb); - - pr_info("AMD IOMMUv2 loaded and initialized\n"); - - return 0; - -out: - return ret; -} - -static void __exit amd_iommu_v2_exit(void) -{ - struct device_state *dev_state, *next; - unsigned long flags; - LIST_HEAD(freelist); - - if (!amd_iommu_v2_supported()) - return; - - amd_iommu_unregister_ppr_notifier(&ppr_nb); - - flush_workqueue(iommu_wq); - - /* - * The loop below might call flush_workqueue(), so call - * destroy_workqueue() after it - */ - spin_lock_irqsave(&state_lock, flags); - - list_for_each_entry_safe(dev_state, next, &state_list, list) { - WARN_ON_ONCE(1); - - put_device_state(dev_state); - list_del(&dev_state->list); - list_add_tail(&dev_state->list, &freelist); - } - - spin_unlock_irqrestore(&state_lock, flags); - - /* - * Since free_device_state waits on the count to be zero, - * we need to free dev_state outside the spinlock. - */ - list_for_each_entry_safe(dev_state, next, &freelist, list) { - list_del(&dev_state->list); - free_device_state(dev_state); - } - - destroy_workqueue(iommu_wq); -} - -module_init(amd_iommu_v2_init); -module_exit(amd_iommu_v2_exit); diff --git a/include/linux/amd-iommu.h b/include/linux/amd-iommu.h index 99a5201d9e625..35ca00b09384c 100644 --- a/include/linux/amd-iommu.h +++ b/include/linux/amd-iommu.h @@ -33,84 +33,6 @@ struct pci_dev; extern int amd_iommu_detect(void); -/** - * amd_iommu_init_device() - Init device for use with IOMMUv2 driver - * @pdev: The PCI device to initialize - * @pasids: Number of PASIDs to support for this device - * - * This function does all setup for the device pdev so that it can be - * used with IOMMUv2. - * Returns 0 on success or negative value on error. - */ -extern int amd_iommu_init_device(struct pci_dev *pdev, int pasids); - -/** - * amd_iommu_free_device() - Free all IOMMUv2 related device resources - * and disable IOMMUv2 usage for this device - * @pdev: The PCI device to disable IOMMUv2 usage for' - */ -extern void amd_iommu_free_device(struct pci_dev *pdev); - -/** - * amd_iommu_bind_pasid() - Bind a given task to a PASID on a device - * @pdev: The PCI device to bind the task to - * @pasid: The PASID on the device the task should be bound to - * @task: the task to bind - * - * The function returns 0 on success or a negative value on error. - */ -extern int amd_iommu_bind_pasid(struct pci_dev *pdev, u32 pasid, - struct task_struct *task); - -/** - * amd_iommu_unbind_pasid() - Unbind a PASID from its task on - * a device - * @pdev: The device of the PASID - * @pasid: The PASID to unbind - * - * When this function returns the device is no longer using the PASID - * and the PASID is no longer bound to its task. - */ -extern void amd_iommu_unbind_pasid(struct pci_dev *pdev, u32 pasid); - -/** - * amd_iommu_set_invalid_ppr_cb() - Register a call-back for failed - * PRI requests - * @pdev: The PCI device the call-back should be registered for - * @cb: The call-back function - * - * The IOMMUv2 driver invokes this call-back when it is unable to - * successfully handle a PRI request. The device driver can then decide - * which PRI response the device should see. Possible return values for - * the call-back are: - * - * - AMD_IOMMU_INV_PRI_RSP_SUCCESS - Send SUCCESS back to the device - * - AMD_IOMMU_INV_PRI_RSP_INVALID - Send INVALID back to the device - * - AMD_IOMMU_INV_PRI_RSP_FAIL - Send Failure back to the device, - * the device is required to disable - * PRI when it receives this response - * - * The function returns 0 on success or negative value on error. - */ -#define AMD_IOMMU_INV_PRI_RSP_SUCCESS 0 -#define AMD_IOMMU_INV_PRI_RSP_INVALID 1 -#define AMD_IOMMU_INV_PRI_RSP_FAIL 2 - -typedef int (*amd_iommu_invalid_ppr_cb)(struct pci_dev *pdev, - u32 pasid, - unsigned long address, - u16); - -extern int amd_iommu_set_invalid_ppr_cb(struct pci_dev *pdev, - amd_iommu_invalid_ppr_cb cb); - -#define PPR_FAULT_EXEC (1 << 1) -#define PPR_FAULT_READ (1 << 2) -#define PPR_FAULT_WRITE (1 << 5) -#define PPR_FAULT_USER (1 << 6) -#define PPR_FAULT_RSVD (1 << 7) -#define PPR_FAULT_GN (1 << 8) - /** * amd_iommu_device_info() - Get information about IOMMUv2 support of a * PCI device @@ -137,22 +59,6 @@ struct amd_iommu_device_info { extern int amd_iommu_device_info(struct pci_dev *pdev, struct amd_iommu_device_info *info); -/** - * amd_iommu_set_invalidate_ctx_cb() - Register a call-back for invalidating - * a pasid context. This call-back is - * invoked when the IOMMUv2 driver needs to - * invalidate a PASID context, for example - * because the task that is bound to that - * context is about to exit. - * - * @pdev: The PCI device the call-back should be registered for - * @cb: The call-back function - */ - -typedef void (*amd_iommu_invalidate_ctx)(struct pci_dev *pdev, u32 pasid); - -extern int amd_iommu_set_invalidate_ctx_cb(struct pci_dev *pdev, - amd_iommu_invalidate_ctx cb); #else /* CONFIG_AMD_IOMMU */ static inline int amd_iommu_detect(void) { return -ENODEV; } -- GitLab From d55b0d2e075ad32d560cdd35a2016973fda52ed6 Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Fri, 6 Oct 2023 09:57:03 +0000 Subject: [PATCH 0418/1451] iommu/amd: Remove PPR support Remove PPR handler and notifier related functions as its not used anymore. Note that we are retaining PPR interrupt handler support as it will be re-used when we introduce IOPF support. Signed-off-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Reviewed-by: Jerry Snitselaar Tested-by: Alex Deucher Link: https://lore.kernel.org/r/20231006095706.5694-3-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/amd_iommu.h | 2 -- drivers/iommu/amd/amd_iommu_types.h | 13 --------- drivers/iommu/amd/iommu.c | 45 +---------------------------- 3 files changed, 1 insertion(+), 59 deletions(-) diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h index 5b8a1e2dd3d03..86be1edd50ee9 100644 --- a/drivers/iommu/amd/amd_iommu.h +++ b/drivers/iommu/amd/amd_iommu.h @@ -52,8 +52,6 @@ int amd_iommu_pc_set_reg(struct amd_iommu *iommu, u8 bank, u8 cntr, int amd_iommu_pdev_enable_cap_pri(struct pci_dev *pdev); void amd_iommu_pdev_disable_cap_pri(struct pci_dev *pdev); -int amd_iommu_register_ppr_notifier(struct notifier_block *nb); -int amd_iommu_unregister_ppr_notifier(struct notifier_block *nb); int amd_iommu_flush_page(struct iommu_domain *dom, u32 pasid, u64 address); void amd_iommu_update_and_flush_device_table(struct protection_domain *domain); void amd_iommu_domain_update(struct protection_domain *domain); diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index 5be563d55ad64..25b731f3d984b 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -509,19 +509,6 @@ extern struct kmem_cache *amd_iommu_irq_cache; #define APERTURE_RANGE_INDEX(a) ((a) >> APERTURE_RANGE_SHIFT) #define APERTURE_PAGE_INDEX(a) (((a) >> 21) & 0x3fULL) -/* - * This struct is used to pass information about - * incoming PPR faults around. - */ -struct amd_iommu_fault { - u64 address; /* IO virtual address of the fault*/ - u32 pasid; /* Address space identifier */ - u32 sbdf; /* Originating PCI device id */ - u16 tag; /* PPR tag */ - u16 flags; /* Fault flags */ - -}; - struct amd_iommu; struct iommu_domain; diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index fd0d7b2f30dce..5abf181f5ecd7 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -64,7 +64,6 @@ LIST_HEAD(acpihid_map); const struct iommu_ops amd_iommu_ops; -static ATOMIC_NOTIFIER_HEAD(ppr_notifier); int amd_iommu_max_glx_val = -1; /* @@ -815,24 +814,6 @@ static void iommu_poll_events(struct amd_iommu *iommu) writel(head, iommu->mmio_base + MMIO_EVT_HEAD_OFFSET); } -static void iommu_handle_ppr_entry(struct amd_iommu *iommu, u64 *raw) -{ - struct amd_iommu_fault fault; - - if (PPR_REQ_TYPE(raw[0]) != PPR_REQ_FAULT) { - pr_err_ratelimited("Unknown PPR request received\n"); - return; - } - - fault.address = raw[1]; - fault.pasid = PPR_PASID(raw[0]); - fault.sbdf = PCI_SEG_DEVID_TO_SBDF(iommu->pci_seg->id, PPR_DEVID(raw[0])); - fault.tag = PPR_TAG(raw[0]); - fault.flags = PPR_FLAGS(raw[0]); - - atomic_notifier_call_chain(&ppr_notifier, 0, &fault); -} - static void iommu_poll_ppr_log(struct amd_iommu *iommu) { u32 head, tail; @@ -878,8 +859,7 @@ static void iommu_poll_ppr_log(struct amd_iommu *iommu) head = (head + PPR_ENTRY_SIZE) % PPR_LOG_SIZE; writel(head, iommu->mmio_base + MMIO_PPR_HEAD_OFFSET); - /* Handle PPR entry */ - iommu_handle_ppr_entry(iommu, entry); + /* TODO: PPR Handler will be added when we add IOPF support */ /* Refresh ring-buffer information */ head = readl(iommu->mmio_base + MMIO_PPR_HEAD_OFFSET); @@ -2545,29 +2525,6 @@ const struct iommu_ops amd_iommu_ops = { } }; -/***************************************************************************** - * - * The next functions do a basic initialization of IOMMU for pass through - * mode - * - * In passthrough mode the IOMMU is initialized and enabled but not used for - * DMA-API translation. - * - *****************************************************************************/ - -/* IOMMUv2 specific functions */ -int amd_iommu_register_ppr_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&ppr_notifier, nb); -} -EXPORT_SYMBOL(amd_iommu_register_ppr_notifier); - -int amd_iommu_unregister_ppr_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&ppr_notifier, nb); -} -EXPORT_SYMBOL(amd_iommu_unregister_ppr_notifier); - static int __flush_pasid(struct protection_domain *domain, u32 pasid, u64 address, bool size) { -- GitLab From 37b282fa04dd7b9bfa7c290fe07ef1730444debb Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Fri, 6 Oct 2023 09:57:04 +0000 Subject: [PATCH 0419/1451] iommu/amd: Remove amd_iommu_device_info() No one is using this function. Hence remove it. Also move PCI device feature detection flags to amd_iommu_types.h as its only used inside AMD IOMMU driver. Signed-off-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Reviewed-by: Jerry Snitselaar Tested-by: Alex Deucher Link: https://lore.kernel.org/r/20231006095706.5694-4-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/amd_iommu_types.h | 8 ++++++ drivers/iommu/amd/iommu.c | 42 ----------------------------- include/linux/amd-iommu.h | 26 ------------------ 3 files changed, 8 insertions(+), 68 deletions(-) diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index 25b731f3d984b..e742006f28852 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -786,6 +786,14 @@ struct devid_map { bool cmd_line; }; +#define AMD_IOMMU_DEVICE_FLAG_ATS_SUP 0x1 /* ATS feature supported */ +#define AMD_IOMMU_DEVICE_FLAG_PRI_SUP 0x2 /* PRI feature supported */ +#define AMD_IOMMU_DEVICE_FLAG_PASID_SUP 0x4 /* PASID context supported */ +/* Device may request execution on memory pages */ +#define AMD_IOMMU_DEVICE_FLAG_EXEC_SUP 0x8 +/* Device may request super-user privileges */ +#define AMD_IOMMU_DEVICE_FLAG_PRIV_SUP 0x10 + /* * This struct contains device specific data for the IOMMU */ diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 5abf181f5ecd7..8f43d89a98dbe 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -2741,48 +2741,6 @@ int amd_iommu_complete_ppr(struct pci_dev *pdev, u32 pasid, } EXPORT_SYMBOL(amd_iommu_complete_ppr); -int amd_iommu_device_info(struct pci_dev *pdev, - struct amd_iommu_device_info *info) -{ - int max_pasids; - int pos; - - if (pdev == NULL || info == NULL) - return -EINVAL; - - if (!amd_iommu_v2_supported()) - return -EINVAL; - - memset(info, 0, sizeof(*info)); - - if (pci_ats_supported(pdev)) - info->flags |= AMD_IOMMU_DEVICE_FLAG_ATS_SUP; - - pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); - if (pos) - info->flags |= AMD_IOMMU_DEVICE_FLAG_PRI_SUP; - - pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID); - if (pos) { - int features; - - max_pasids = 1 << (9 * (amd_iommu_max_glx_val + 1)); - max_pasids = min(max_pasids, (1 << 20)); - - info->flags |= AMD_IOMMU_DEVICE_FLAG_PASID_SUP; - info->max_pasids = min(pci_max_pasids(pdev), max_pasids); - - features = pci_pasid_features(pdev); - if (features & PCI_PASID_CAP_EXEC) - info->flags |= AMD_IOMMU_DEVICE_FLAG_EXEC_SUP; - if (features & PCI_PASID_CAP_PRIV) - info->flags |= AMD_IOMMU_DEVICE_FLAG_PRIV_SUP; - } - - return 0; -} -EXPORT_SYMBOL(amd_iommu_device_info); - #ifdef CONFIG_IRQ_REMAP /***************************************************************************** diff --git a/include/linux/amd-iommu.h b/include/linux/amd-iommu.h index 35ca00b09384c..dc7ed2f468861 100644 --- a/include/linux/amd-iommu.h +++ b/include/linux/amd-iommu.h @@ -33,32 +33,6 @@ struct pci_dev; extern int amd_iommu_detect(void); -/** - * amd_iommu_device_info() - Get information about IOMMUv2 support of a - * PCI device - * @pdev: PCI device to query information from - * @info: A pointer to an amd_iommu_device_info structure which will contain - * the information about the PCI device - * - * Returns 0 on success, negative value on error - */ - -#define AMD_IOMMU_DEVICE_FLAG_ATS_SUP 0x1 /* ATS feature supported */ -#define AMD_IOMMU_DEVICE_FLAG_PRI_SUP 0x2 /* PRI feature supported */ -#define AMD_IOMMU_DEVICE_FLAG_PASID_SUP 0x4 /* PASID context supported */ -#define AMD_IOMMU_DEVICE_FLAG_EXEC_SUP 0x8 /* Device may request execution - on memory pages */ -#define AMD_IOMMU_DEVICE_FLAG_PRIV_SUP 0x10 /* Device may request - super-user privileges */ - -struct amd_iommu_device_info { - int max_pasids; - u32 flags; -}; - -extern int amd_iommu_device_info(struct pci_dev *pdev, - struct amd_iommu_device_info *info); - #else /* CONFIG_AMD_IOMMU */ static inline int amd_iommu_detect(void) { return -ENODEV; } -- GitLab From 45d08d85e6f64d3f1002ce2eb5c967e2aa4bcd39 Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Fri, 6 Oct 2023 09:57:05 +0000 Subject: [PATCH 0420/1451] iommu/amd: Remove unused EXPORT_SYMBOLS Drop EXPORT_SYMBOLS for the functions that are not used by any modules. Signed-off-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Reviewed-by: Jerry Snitselaar Tested-by: Alex Deucher Link: https://lore.kernel.org/r/20231006095706.5694-5-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/init.c | 1 - drivers/iommu/amd/iommu.c | 6 ------ 2 files changed, 7 deletions(-) diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index 463e68a88b174..64bcf3df37ee5 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -3666,7 +3666,6 @@ bool amd_iommu_v2_supported(void) */ return amd_iommu_gt_ppr_supported() && !amd_iommu_snp_en; } -EXPORT_SYMBOL(amd_iommu_v2_supported); struct amd_iommu *get_amd_iommu(unsigned int idx) { diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 8f43d89a98dbe..d996a6f22a5fc 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -2446,7 +2446,6 @@ bool amd_iommu_is_attach_deferred(struct device *dev) return dev_data->defer_attach; } -EXPORT_SYMBOL_GPL(amd_iommu_is_attach_deferred); static void amd_iommu_flush_iotlb_all(struct iommu_domain *domain) { @@ -2606,7 +2605,6 @@ int amd_iommu_flush_page(struct iommu_domain *dom, u32 pasid, return ret; } -EXPORT_SYMBOL(amd_iommu_flush_page); static int __amd_iommu_flush_tlb(struct protection_domain *domain, u32 pasid) { @@ -2626,7 +2624,6 @@ int amd_iommu_flush_tlb(struct iommu_domain *dom, u32 pasid) return ret; } -EXPORT_SYMBOL(amd_iommu_flush_tlb); static u64 *__get_gcr3_pte(u64 *root, int level, u32 pasid, bool alloc) { @@ -2706,7 +2703,6 @@ int amd_iommu_domain_set_gcr3(struct iommu_domain *dom, u32 pasid, return ret; } -EXPORT_SYMBOL(amd_iommu_domain_set_gcr3); int amd_iommu_domain_clear_gcr3(struct iommu_domain *dom, u32 pasid) { @@ -2720,7 +2716,6 @@ int amd_iommu_domain_clear_gcr3(struct iommu_domain *dom, u32 pasid) return ret; } -EXPORT_SYMBOL(amd_iommu_domain_clear_gcr3); int amd_iommu_complete_ppr(struct pci_dev *pdev, u32 pasid, int status, int tag) @@ -2739,7 +2734,6 @@ int amd_iommu_complete_ppr(struct pci_dev *pdev, u32 pasid, return iommu_queue_command(iommu, &cmd); } -EXPORT_SYMBOL(amd_iommu_complete_ppr); #ifdef CONFIG_IRQ_REMAP -- GitLab From 189116d5ad54eee2bab82c5f12e837912fc0b4c4 Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Fri, 6 Oct 2023 09:57:06 +0000 Subject: [PATCH 0421/1451] Revert "iommu: Fix false ownership failure on AMD systems with PASID activated" This reverts commit 2380f1e8195ef612deea1dc7a3d611c5d2b9b56a. Previous patch removed AMD iommu_v2 module. Hence its safe to revert this workaround. Suggested-by: Jason Gunthorpe Cc: Robin Murphy Cc: Takashi Iwai Cc: Jason Gunthorpe Cc: Joerg Roedel Signed-off-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20231006095706.5694-6-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 3bfc56df4f781..360f1042e5550 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -3113,24 +3113,6 @@ static ssize_t iommu_group_store_type(struct iommu_group *group, return ret ?: count; } -static bool iommu_is_default_domain(struct iommu_group *group) -{ - if (group->domain == group->default_domain) - return true; - - /* - * If the default domain was set to identity and it is still an identity - * domain then we consider this a pass. This happens because of - * amd_iommu_init_device() replacing the default idenytity domain with an - * identity domain that has a different configuration for AMDGPU. - */ - if (group->default_domain && - group->default_domain->type == IOMMU_DOMAIN_IDENTITY && - group->domain && group->domain->type == IOMMU_DOMAIN_IDENTITY) - return true; - return false; -} - /** * iommu_device_use_default_domain() - Device driver wants to handle device * DMA through the kernel DMA API. @@ -3149,7 +3131,7 @@ int iommu_device_use_default_domain(struct device *dev) mutex_lock(&group->mutex); if (group->owner_cnt) { - if (group->owner || !iommu_is_default_domain(group) || + if (group->domain != group->default_domain || group->owner || !xa_empty(&group->pasid_array)) { ret = -EBUSY; goto unlock_out; -- GitLab From a8ca9fc9134c1a43e6d4db7ff59496bbd7075def Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 5 Oct 2023 10:35:11 -0300 Subject: [PATCH 0422/1451] powerpc/iommu: Do not do platform domain attach atctions after probe POWER throws a splat at boot, it looks like the DMA ops were probably changed while a driver was attached. Something is still weird about how power sequences its bootup. Previously this was hidden since the core iommu code did nothing during probe, now it calls spapr_tce_platform_iommu_attach_dev(). Make spapr_tce_platform_iommu_attach_dev() do nothing on the probe time call like it did before. WARNING: CPU: 0 PID: 8 at arch/powerpc/kernel/iommu.c:407 __iommu_free+0x1e4/0x1f0 Modules linked in: sd_mod t10_pi crc64_rocksoft crc64 sg ibmvfc mlx5_core(+) scsi_transport_fc ibmveth mlxfw psample dm_multipath dm_mirror dm_region_hash dm_log dm_mod fuse CPU: 0 PID: 8 Comm: kworker/0:0 Not tainted 6.6.0-rc3-next-20230929-auto #1 Hardware name: IBM,9080-HEX POWER10 (raw) 0x800200 0xf000006 of:IBM,FW1030.30 (NH1030_062) hv:phyp pSeries Workqueue: events work_for_cpu_fn NIP: c00000000005f6d4 LR: c00000000005f6d0 CTR: 00000000005ca81c REGS: c000000003a27890 TRAP: 0700 Not tainted (6.6.0-rc3-next-20230929-auto) MSR: 800000000282b033 CR: 48000824 XER: 00000008 CFAR: c00000000020f738 IRQMASK: 0 GPR00: c00000000005f6d0 c000000003a27b30 c000000001481800 000000000000017 GPR04: 00000000ffff7fff c000000003a27950 c000000003a27948 0000000000000027 GPR08: c000000c18c07c10 0000000000000001 0000000000000027 c000000002ac8a08 GPR12: 0000000000000000 c000000002ff0000 c00000000019cc88 c000000003042300 GPR16: 0000000000000000 0000000000000000 0000000000000000 c000000003071ab0 GPR20: c00000000349f80d c000000003215440 c000000003215480 61c8864680b583eb GPR24: 0000000000000000 000000007fffffff 0800000020000000 0000000000000010 GPR28: 0000000000020000 0000800000020000 c00000000c5dc800 c00000000c5dc880 NIP [c00000000005f6d4] __iommu_free+0x1e4/0x1f0 LR [c00000000005f6d0] __iommu_free+0x1e0/0x1f0 Call Trace: [c000000003a27b30] [c00000000005f6d0] __iommu_free+0x1e0/0x1f0 (unreliable) [c000000003a27bc0] [c00000000005f848] iommu_free+0x28/0x70 [c000000003a27bf0] [c000000000061518] iommu_free_coherent+0x68/0xa0 [c000000003a27c20] [c00000000005e8d4] dma_iommu_free_coherent+0x24/0x40 [c000000003a27c40] [c00000000024698c] dma_free_attrs+0x10c/0x140 [c000000003a27c90] [c008000000dcb8d4] mlx5_cmd_cleanup+0x5c/0x90 [mlx5_core] [c000000003a27cc0] [c008000000dc45a0] mlx5_mdev_uninit+0xc8/0x100 [mlx5_core] [c000000003a27d00] [c008000000dc4ac4] probe_one+0x3ec/0x530 [mlx5_core] [c000000003a27d90] [c0000000008c5edc] local_pci_probe+0x6c/0x110 [c000000003a27e10] [c000000000189c98] work_for_cpu_fn+0x38/0x60 [c000000003a27e40] [c00000000018d1d0] process_scheduled_works+0x230/0x4f0 [c000000003a27f10] [c00000000018ff14] worker_thread+0x1e4/0x500 [c000000003a27f90] [c00000000019cdb8] kthread+0x138/0x140 [c000000003a27fe0] [c00000000000df98] start_kernel_thread+0x14/0x18 Code: 481b004d 60000000 e89e0028 3c62ffe0 3863dd20 481b0039 60000000 e89e0038 3c62ffe0 3863dd38 481b0025 60000000 <0fe00000> 4bffff20 60000000 3c4c0142 ---[ end trace 0000000000000000 ]--- iommu_free: invalid entry entry = 0x8000000203d0 dma_addr = 0x8000000203d0000 Table = 0xc00000000c5dc800 bus# = 0x1 size = 0x20000 startOff = 0x800000000000 index = 0x70200016 Fixes: 2ad56efa80db ("powerpc/iommu: Setup a default domain and remove set_platform_dma_ops") Reported-by: Tasmiya Nalatwad Link: https://lore.kernel.org/r/d06cee81-c47f-9d62-dfc6-4c77b60058db@linux.vnet.ibm.com Tested-by: Tasmiya Nalatwad Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/0-v1-2b52423411b9+164fc-iommu_ppc_defdomain_jgg@nvidia.com Signed-off-by: Joerg Roedel --- arch/powerpc/kernel/iommu.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index d6ad3fde85a21..bf19932147517 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -1280,13 +1280,19 @@ struct iommu_table_group_ops spapr_tce_table_group_ops = { /* * A simple iommu_ops to allow less cruft in generic VFIO code. */ -static int spapr_tce_platform_iommu_attach_dev(struct iommu_domain *dom, - struct device *dev) +static int +spapr_tce_platform_iommu_attach_dev(struct iommu_domain *platform_domain, + struct device *dev) { + struct iommu_domain *domain = iommu_get_domain_for_dev(dev); struct iommu_group *grp = iommu_group_get(dev); struct iommu_table_group *table_group; int ret = -EINVAL; + /* At first attach the ownership is already set */ + if (!domain) + return 0; + if (!grp) return -ENODEV; -- GitLab From 0ab13674a9bd10514486cf1670d71dbd8afec421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Mon, 25 Sep 2023 16:36:04 +0200 Subject: [PATCH 0423/1451] media: pci: mgb4: Added Digiteq Automotive MGB4 driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Digiteq Automotive MGB4 is a modular frame grabber PCIe card for automotive video interfaces. As for now, two modules - FPD-Link and GMSL - are available and supported by the driver. The card has two inputs and two outputs (FPD-Link only). In addition to the video interfaces it also provides a trigger signal interface and a MTD interface for FPGA firmware upload. Signed-off-by: Martin Tůma Signed-off-by: Hans Verkuil --- MAINTAINERS | 7 + drivers/media/pci/Kconfig | 1 + drivers/media/pci/Makefile | 1 + drivers/media/pci/mgb4/Kconfig | 17 + drivers/media/pci/mgb4/Makefile | 6 + drivers/media/pci/mgb4/mgb4_cmt.c | 244 ++++++ drivers/media/pci/mgb4/mgb4_cmt.h | 17 + drivers/media/pci/mgb4/mgb4_core.c | 686 +++++++++++++++++ drivers/media/pci/mgb4/mgb4_core.h | 74 ++ drivers/media/pci/mgb4/mgb4_dma.c | 123 ++++ drivers/media/pci/mgb4/mgb4_dma.h | 18 + drivers/media/pci/mgb4/mgb4_i2c.c | 140 ++++ drivers/media/pci/mgb4/mgb4_i2c.h | 35 + drivers/media/pci/mgb4/mgb4_io.h | 33 + drivers/media/pci/mgb4/mgb4_regs.c | 30 + drivers/media/pci/mgb4/mgb4_regs.h | 35 + drivers/media/pci/mgb4/mgb4_sysfs.h | 18 + drivers/media/pci/mgb4/mgb4_sysfs_in.c | 772 +++++++++++++++++++ drivers/media/pci/mgb4/mgb4_sysfs_out.c | 737 +++++++++++++++++++ drivers/media/pci/mgb4/mgb4_sysfs_pci.c | 71 ++ drivers/media/pci/mgb4/mgb4_trigger.c | 208 ++++++ drivers/media/pci/mgb4/mgb4_trigger.h | 8 + drivers/media/pci/mgb4/mgb4_vin.c | 939 ++++++++++++++++++++++++ drivers/media/pci/mgb4/mgb4_vin.h | 69 ++ drivers/media/pci/mgb4/mgb4_vout.c | 602 +++++++++++++++ drivers/media/pci/mgb4/mgb4_vout.h | 65 ++ 26 files changed, 4956 insertions(+) create mode 100644 drivers/media/pci/mgb4/Kconfig create mode 100644 drivers/media/pci/mgb4/Makefile create mode 100644 drivers/media/pci/mgb4/mgb4_cmt.c create mode 100644 drivers/media/pci/mgb4/mgb4_cmt.h create mode 100644 drivers/media/pci/mgb4/mgb4_core.c create mode 100644 drivers/media/pci/mgb4/mgb4_core.h create mode 100644 drivers/media/pci/mgb4/mgb4_dma.c create mode 100644 drivers/media/pci/mgb4/mgb4_dma.h create mode 100644 drivers/media/pci/mgb4/mgb4_i2c.c create mode 100644 drivers/media/pci/mgb4/mgb4_i2c.h create mode 100644 drivers/media/pci/mgb4/mgb4_io.h create mode 100644 drivers/media/pci/mgb4/mgb4_regs.c create mode 100644 drivers/media/pci/mgb4/mgb4_regs.h create mode 100644 drivers/media/pci/mgb4/mgb4_sysfs.h create mode 100644 drivers/media/pci/mgb4/mgb4_sysfs_in.c create mode 100644 drivers/media/pci/mgb4/mgb4_sysfs_out.c create mode 100644 drivers/media/pci/mgb4/mgb4_sysfs_pci.c create mode 100644 drivers/media/pci/mgb4/mgb4_trigger.c create mode 100644 drivers/media/pci/mgb4/mgb4_trigger.h create mode 100644 drivers/media/pci/mgb4/mgb4_vin.c create mode 100644 drivers/media/pci/mgb4/mgb4_vin.h create mode 100644 drivers/media/pci/mgb4/mgb4_vout.c create mode 100644 drivers/media/pci/mgb4/mgb4_vout.h diff --git a/MAINTAINERS b/MAINTAINERS index 03dae6ab6a888..bba09f9d01418 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6087,6 +6087,13 @@ L: linux-gpio@vger.kernel.org S: Maintained F: drivers/gpio/gpio-gpio-mm.c +DIGITEQ AUTOMOTIVE MGB4 V4L2 DRIVER +M: Martin Tuma +L: linux-media@vger.kernel.org +S: Maintained +F: Documentation/admin-guide/media/mgb4.rst +F: drivers/media/pci/mgb4/ + DIOLAN U2C-12 I2C DRIVER M: Guenter Roeck L: linux-i2c@vger.kernel.org diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index ee095bde0b686..7f65aa6093883 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig @@ -13,6 +13,7 @@ if MEDIA_PCI_SUPPORT if MEDIA_CAMERA_SUPPORT comment "Media capture support" +source "drivers/media/pci/mgb4/Kconfig" source "drivers/media/pci/solo6x10/Kconfig" source "drivers/media/pci/sta2x11/Kconfig" source "drivers/media/pci/tw5864/Kconfig" diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile index 8bed619b71306..f18c7e15abe3e 100644 --- a/drivers/media/pci/Makefile +++ b/drivers/media/pci/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_VIDEO_CX25821) += cx25821/ obj-$(CONFIG_VIDEO_CX88) += cx88/ obj-$(CONFIG_VIDEO_DT3155) += dt3155/ obj-$(CONFIG_VIDEO_IVTV) += ivtv/ +obj-$(CONFIG_VIDEO_MGB4) += mgb4/ obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10/ diff --git a/drivers/media/pci/mgb4/Kconfig b/drivers/media/pci/mgb4/Kconfig new file mode 100644 index 0000000000000..13fad15a434c4 --- /dev/null +++ b/drivers/media/pci/mgb4/Kconfig @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only +config VIDEO_MGB4 + tristate "Digiteq Automotive MGB4 support" + depends on VIDEO_DEV && PCI && I2C && DMADEVICES && SPI && MTD && IIO + select VIDEOBUF2_DMA_SG + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select I2C_XILINX + select SPI_XILINX + select MTD_SPI_NOR + select XILINX_XDMA + help + This is a video4linux driver for Digiteq Automotive MGB4 grabber + cards. + + To compile this driver as a module, choose M here: the + module will be called mgb4. diff --git a/drivers/media/pci/mgb4/Makefile b/drivers/media/pci/mgb4/Makefile new file mode 100644 index 0000000000000..e92ead18bed08 --- /dev/null +++ b/drivers/media/pci/mgb4/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +mgb4-objs := mgb4_regs.o mgb4_core.o mgb4_vin.o mgb4_vout.o \ + mgb4_sysfs_pci.o mgb4_sysfs_in.o mgb4_sysfs_out.o \ + mgb4_i2c.o mgb4_cmt.o mgb4_trigger.o mgb4_dma.o + +obj-$(CONFIG_VIDEO_MGB4) += mgb4.o diff --git a/drivers/media/pci/mgb4/mgb4_cmt.c b/drivers/media/pci/mgb4/mgb4_cmt.c new file mode 100644 index 0000000000000..70dc78ef193c7 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_cmt.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma + * + * The CMT module configures the FPGA Clock Management Tile (CMT) registers. For + * different video signal frequencies (FPGA input signal frequencies), the FPGA + * CMT registers need to be adjusted for the FPGA to work properly. The values + * are precomputed based on formulas given by Xilinx in their FPGA documentation + * (which are in turn full of some magic values/tables...). + */ + +#include +#include +#include "mgb4_core.h" +#include "mgb4_cmt.h" + +static const u16 cmt_vals_out[][15] = { + {0x1208, 0x0000, 0x171C, 0x0000, 0x1E38, 0x0000, 0x11C7, 0x0000, 0x1041, 0x01BC, 0x7C01, 0x7DE9, 0xFFFF, 0x9900, 0x8100, }, + {0x11C7, 0x0000, 0x1619, 0x0080, 0x1C71, 0x0000, 0x130D, 0x0080, 0x0041, 0x0090, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x9000, }, + {0x11C7, 0x0000, 0x1619, 0x0080, 0x1C71, 0x0000, 0x165A, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x11C7, 0x0000, 0x1619, 0x0080, 0x1C71, 0x0000, 0x1187, 0x0080, 0x1041, 0x01EE, 0x7C01, 0x7DE9, 0xFFFF, 0x9900, 0x8100, }, + {0x1186, 0x0000, 0x1555, 0x0000, 0x1AAA, 0x0000, 0x1451, 0x0000, 0x0042, 0x0013, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x11C7, 0x0000, 0x1619, 0x0080, 0x1C71, 0x0000, 0x134E, 0x0080, 0x0041, 0x005E, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x1619, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x179E, 0x0000, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x179F, 0x0080, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x17DF, 0x0000, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x8800, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x128B, 0x0080, 0x0041, 0x00DB, 0x7C01, 0x7DE9, 0xFFFF, 0x9000, 0x0100, }, + {0x1186, 0x0000, 0x1555, 0x0000, 0x1AAA, 0x0000, 0x1820, 0x0000, 0x0083, 0x00FA, 0x7DE9, 0x7DE8, 0xFFFF, 0x0900, 0x9000, }, + {0x1186, 0x0000, 0x1555, 0x0000, 0x1AAA, 0x0000, 0x1187, 0x0080, 0x1041, 0x01EE, 0x7C01, 0x7DE9, 0xFFFF, 0x9900, 0x8100, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x169B, 0x0080, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1800, 0x0100, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x171C, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x1800, }, + {0x1186, 0x0000, 0x1555, 0x0000, 0x1AAA, 0x0000, 0x1515, 0x0080, 0x0042, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x1493, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x15D8, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1900, 0x0100, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x124A, 0x0080, 0x0041, 0x010D, 0x7C01, 0x7DE9, 0xFFFF, 0x9000, 0x0100, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x175D, 0x0000, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x1619, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x17DF, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x8800, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x17E0, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x9000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x1820, 0x0000, 0x0083, 0x00FA, 0x7DE9, 0x7DE8, 0xFFFF, 0x0900, 0x9000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x13D0, 0x0080, 0x0042, 0x002C, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x128B, 0x0080, 0x0041, 0x00DB, 0x7C01, 0x7DE9, 0xFFFF, 0x9000, 0x0100, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x1820, 0x0000, 0x00C3, 0x00FA, 0x7DE9, 0x7DE8, 0xFFFF, 0x0900, 0x9000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x134E, 0x0080, 0x0041, 0x005E, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x1515, 0x0080, 0x0042, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x175D, 0x0000, 0x00C4, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x11C7, 0x0000, 0x1041, 0x01BC, 0x7C01, 0x7DE9, 0xFFFF, 0x9900, 0x8100, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1209, 0x0080, 0x0041, 0x013F, 0x7C01, 0x7DE9, 0xFFFF, 0x9900, 0x1100, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1556, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x8000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x179F, 0x0080, 0x00C4, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x15D8, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1900, 0x0100, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1105, 0x0080, 0x1041, 0x01E8, 0x6401, 0x65E9, 0xFFFF, 0x9800, 0x1100, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1820, 0x0000, 0x00C4, 0x00FA, 0x7DE9, 0x7DE8, 0xFFFF, 0x0900, 0x9000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x1493, 0x0080, 0x0042, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x138E, 0x0000, 0x0042, 0x005E, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x17E0, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x9000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x165A, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x175D, 0x0000, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x1187, 0x0080, 0x1041, 0x01EE, 0x7C01, 0x7DE9, 0xFFFF, 0x9900, 0x8100, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x175E, 0x0080, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x179E, 0x0000, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x134E, 0x0080, 0x0041, 0x005E, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x165A, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x16DC, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x1800, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x169A, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x11C7, 0x0000, 0x1041, 0x01BC, 0x7C01, 0x7DE9, 0xFFFF, 0x9900, 0x8100, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x169B, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1800, 0x0100, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x171D, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x1800, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x16DB, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1800, 0x0100, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1146, 0x0080, 0x1041, 0x0184, 0x7C01, 0x7DE9, 0xFFFF, 0x9900, 0x8100, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x171C, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x1800, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1451, 0x0000, 0x0042, 0x0013, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x171D, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x1800, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x175D, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1452, 0x0080, 0x0042, 0x0013, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x15D8, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1900, 0x0100, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1104, 0x0000, 0x1041, 0x01E8, 0x5801, 0x59E9, 0xFFFF, 0x9900, 0x0900, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x179F, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1515, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x17DF, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x8800, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1659, 0x0000, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1555, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x8000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x14D3, 0x0000, 0x0042, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1820, 0x0000, 0x0083, 0x00FA, 0x7DE9, 0x7DE8, 0xFFFF, 0x0900, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1556, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x8000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1187, 0x0080, 0x1041, 0x01EE, 0x7C01, 0x7DE9, 0xFFFF, 0x9900, 0x8100, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1452, 0x0080, 0x0082, 0x0013, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x169B, 0x0080, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1800, 0x0100, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1514, 0x0000, 0x0042, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x17E0, 0x0080, 0x00C4, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x9000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1515, 0x0080, 0x0042, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x16DC, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x1800, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1493, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x1800, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x15D8, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1900, 0x0100, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x171D, 0x0080, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x1800, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1618, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1900, 0x0100, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x175D, 0x0000, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x14D4, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1619, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x179E, 0x0000, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x179F, 0x0080, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1515, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x13D0, 0x0080, 0x0042, 0x002C, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x169A, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x128B, 0x0080, 0x0041, 0x00DB, 0x7C01, 0x7DE9, 0xFFFF, 0x9000, 0x0100, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x169B, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1800, 0x0100, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1820, 0x0000, 0x00C3, 0x00FA, 0x7DE9, 0x7DE8, 0xFFFF, 0x0900, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1556, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x8000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x16DB, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1800, 0x0100, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1411, 0x0080, 0x0042, 0x002C, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x1800, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1597, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x8000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1451, 0x0000, 0x0042, 0x0013, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x171D, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x1800, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x12CC, 0x0080, 0x0041, 0x00A9, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x175D, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1452, 0x0080, 0x0042, 0x0013, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x15D8, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1900, 0x0100, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x175E, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1492, 0x0000, 0x0042, 0x0013, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x179F, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1619, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1493, 0x0080, 0x0042, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x17DF, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x8800, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x130D, 0x0080, 0x0041, 0x0090, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x17E0, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x14D3, 0x0000, 0x0042, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x165A, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1820, 0x0000, 0x0083, 0x00FA, 0x7DE9, 0x7DE8, 0xFFFF, 0x0900, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x14D4, 0x0080, 0x0042, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x169B, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1800, 0x0100, }, +}; + +static const u16 cmt_vals_in[][13] = { + {0x1082, 0x0000, 0x5104, 0x0000, 0x11C7, 0x0000, 0x1041, 0x02BC, 0x7C01, 0xFFE9, 0x9900, 0x9908, 0x8100}, + {0x1104, 0x0000, 0x9208, 0x0000, 0x138E, 0x0000, 0x1041, 0x015E, 0x7C01, 0xFFE9, 0x0100, 0x0908, 0x1000}, +}; + +static const u32 cmt_addrs_out[][15] = { + {0x420, 0x424, 0x428, 0x42C, 0x430, 0x434, 0x450, 0x454, 0x458, 0x460, 0x464, 0x468, 0x4A0, 0x538, 0x53C}, + {0x620, 0x624, 0x628, 0x62C, 0x630, 0x634, 0x650, 0x654, 0x658, 0x660, 0x664, 0x668, 0x6A0, 0x738, 0x73C}, +}; + +static const u32 cmt_addrs_in[][13] = { + {0x020, 0x024, 0x028, 0x02C, 0x050, 0x054, 0x058, 0x060, 0x064, 0x068, 0x0A0, 0x138, 0x13C}, + {0x220, 0x224, 0x228, 0x22C, 0x250, 0x254, 0x258, 0x260, 0x264, 0x268, 0x2A0, 0x338, 0x33C}, +}; + +static const u32 cmt_freq[] = { + 25000, 25510, 26020, 26530, 26983, 27551, 28000, 28570, + 29046, 29522, 30000, 30476, 30952, 31546, 32000, 32539, + 33035, 33571, 33928, 34522, 35000, 35428, 36000, 36571, + 36904, 37500, 38093, 38571, 39047, 39453, 40000, 40476, + 40952, 41494, 41964, 42857, 43535, 44047, 44444, 45000, + 45535, 46029, 46428, 46823, 47617, 48214, 48571, 49107, + 49523, 50000, 50476, 50892, 51428, 52380, 53333, 53967, + 54285, 55238, 55555, 55952, 57142, 58095, 58571, 59047, + 59521, 60000, 60316, 60952, 61428, 61904, 62500, 63092, + 63491, 64282, 65078, 65476, 66071, 66664, 67142, 67854, + 68571, 69044, 69642, 70000, 71425, 72616, 73214, 73808, + 74285, 75000, 75714, 76187, 76785, 77142, 78570, 80000, + 80357, 80951, 81428, 82142, 82857, 83332, 83928, 84285, + 85713, 87142, 87500, 88094, 88571, 89285, 90000, 90475, + 91071, 91428, 92856, 94642, +}; + +static size_t freq_srch(u32 key, const u32 *array, size_t size) +{ + int l = 0; + int r = size - 1; + int m = 0; + + while (l <= r) { + m = (l + r) / 2; + if (array[m] < key) + l = m + 1; + else if (array[m] > key) + r = m - 1; + else + return m; + } + + if (r < 0 || l > size - 1) + return m; + else + return (abs(key - array[l]) < abs(key - array[r])) ? l : r; +} + +u32 mgb4_cmt_set_vout_freq(struct mgb4_vout_dev *voutdev, unsigned int freq) +{ + struct mgb4_regs *video = &voutdev->mgbdev->video; + const struct mgb4_vout_regs *regs = &voutdev->config->regs; + const u16 *reg_set; + const u32 *addr; + u32 config; + size_t i, index; + + index = freq_srch(freq, cmt_freq, ARRAY_SIZE(cmt_freq)); + addr = cmt_addrs_out[voutdev->config->id]; + reg_set = cmt_vals_out[index]; + + config = mgb4_read_reg(video, regs->config); + + mgb4_write_reg(video, regs->config, 0x1 | (config & ~0x3)); + + for (i = 0; i < ARRAY_SIZE(cmt_addrs_out[0]); i++) + mgb4_write_reg(&voutdev->mgbdev->cmt, addr[i], reg_set[i]); + + mgb4_mask_reg(video, regs->config, 0x100, 0x100); + mgb4_mask_reg(video, regs->config, 0x100, 0x0); + + mgb4_write_reg(video, regs->config, config & ~0x1); + + return cmt_freq[index]; +} + +void mgb4_cmt_set_vin_freq_range(struct mgb4_vin_dev *vindev, + unsigned int freq_range) +{ + struct mgb4_regs *video = &vindev->mgbdev->video; + const struct mgb4_vin_regs *regs = &vindev->config->regs; + const u16 *reg_set; + const u32 *addr; + u32 config; + size_t i; + + addr = cmt_addrs_in[vindev->config->id]; + reg_set = cmt_vals_in[freq_range]; + + config = mgb4_read_reg(video, regs->config); + + mgb4_write_reg(video, regs->config, 0x1 | (config & ~0x3)); + + for (i = 0; i < ARRAY_SIZE(cmt_addrs_in[0]); i++) + mgb4_write_reg(&vindev->mgbdev->cmt, addr[i], reg_set[i]); + + mgb4_mask_reg(video, regs->config, 0x1000, 0x1000); + mgb4_mask_reg(video, regs->config, 0x1000, 0x0); + + mgb4_write_reg(video, regs->config, config & ~0x1); +} diff --git a/drivers/media/pci/mgb4/mgb4_cmt.h b/drivers/media/pci/mgb4/mgb4_cmt.h new file mode 100644 index 0000000000000..b15df56ca0596 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_cmt.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma + */ + +#ifndef __MGB4_CMT_H__ +#define __MGB4_CMT_H__ + +#include "mgb4_vout.h" +#include "mgb4_vin.h" + +u32 mgb4_cmt_set_vout_freq(struct mgb4_vout_dev *voutdev, unsigned int freq); +void mgb4_cmt_set_vin_freq_range(struct mgb4_vin_dev *vindev, + unsigned int freq_range); + +#endif diff --git a/drivers/media/pci/mgb4/mgb4_core.c b/drivers/media/pci/mgb4/mgb4_core.c new file mode 100644 index 0000000000000..3efb33fbf40cc --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_core.c @@ -0,0 +1,686 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This is the driver for the MGB4 video grabber card by Digiteq Automotive. + * + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma + * + * This is the main driver module. The DMA, I2C and SPI sub-drivers are + * initialized here and the input/output v4l2 devices are created. + * + * The mgb4 card uses different expansion modules for different video sources + * (GMSL and FPDL3 for now) so in probe() we detect the module type based on + * what we see on the I2C bus and check if it matches the FPGA bitstream (there + * are different bitstreams for different expansion modules). When no expansion + * module is present, we still let the driver initialize to allow flashing of + * the FPGA firmware using the SPI FLASH device. No v4l2 video devices are + * created in this case. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mgb4_dma.h" +#include "mgb4_i2c.h" +#include "mgb4_sysfs.h" +#include "mgb4_vout.h" +#include "mgb4_vin.h" +#include "mgb4_trigger.h" +#include "mgb4_core.h" + +#define MGB4_USER_IRQS 16 + +ATTRIBUTE_GROUPS(mgb4_pci); + +static int flashid; + +static struct xdma_chan_info h2c_chan_info = { + .dir = DMA_MEM_TO_DEV, +}; + +static struct xdma_chan_info c2h_chan_info = { + .dir = DMA_DEV_TO_MEM, +}; + +static struct xspi_platform_data spi_platform_data = { + .num_chipselect = 1, + .bits_per_word = 8 +}; + +static const struct i2c_board_info extender_info = { + I2C_BOARD_INFO("extender", 0x21) +}; + +#if IS_REACHABLE(CONFIG_HWMON) +static umode_t temp_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + if (type == hwmon_temp && + (attr == hwmon_temp_input || attr == hwmon_temp_label)) + return 0444; + else + return 0; +} + +static int temp_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, + int channel, long *val) +{ + struct mgb4_dev *mgbdev = dev_get_drvdata(dev); + u32 val10, raw; + + if (type != hwmon_temp || attr != hwmon_temp_input) + return -EOPNOTSUPP; + + raw = mgb4_read_reg(&mgbdev->video, 0xD0); + /* register value -> Celsius degrees formula given by Xilinx */ + val10 = ((((raw >> 20) & 0xFFF) * 503975) - 1118822400) / 409600; + *val = val10 * 100; + + return 0; +} + +static int temp_read_string(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, const char **str) +{ + if (type != hwmon_temp || attr != hwmon_temp_label) + return -EOPNOTSUPP; + + *str = "FPGA Temperature"; + + return 0; +} + +static const struct hwmon_ops temp_ops = { + .is_visible = temp_is_visible, + .read = temp_read, + .read_string = temp_read_string +}; + +static const struct hwmon_channel_info *temp_channel_info[] = { + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_LABEL), + NULL +}; + +static const struct hwmon_chip_info temp_chip_info = { + .ops = &temp_ops, + .info = temp_channel_info, +}; +#endif + +static int match_i2c_adap(struct device *dev, void *data) +{ + return i2c_verify_adapter(dev) ? 1 : 0; +} + +static struct i2c_adapter *get_i2c_adap(struct platform_device *pdev) +{ + struct device *dev; + + mutex_lock(&pdev->dev.mutex); + dev = device_find_child(&pdev->dev, NULL, match_i2c_adap); + mutex_unlock(&pdev->dev.mutex); + + return dev ? to_i2c_adapter(dev) : NULL; +} + +static int match_spi_adap(struct device *dev, void *data) +{ + return to_spi_device(dev) ? 1 : 0; +} + +static struct spi_master *get_spi_adap(struct platform_device *pdev) +{ + struct device *dev; + + mutex_lock(&pdev->dev.mutex); + dev = device_find_child(&pdev->dev, NULL, match_spi_adap); + mutex_unlock(&pdev->dev.mutex); + + return dev ? container_of(dev, struct spi_master, dev) : NULL; +} + +static int init_spi(struct mgb4_dev *mgbdev) +{ + struct resource spi_resources[] = { + { + .start = 0x400, + .end = 0x47f, + .flags = IORESOURCE_MEM, + .name = "io-memory", + }, + { + .start = 14, + .end = 14, + .flags = IORESOURCE_IRQ, + .name = "irq", + }, + }; + struct spi_board_info spi_info = { + .max_speed_hz = 10000000, + .modalias = "m25p80", + .chip_select = 0, + .mode = SPI_MODE_3, + }; + struct pci_dev *pdev = mgbdev->pdev; + struct device *dev = &pdev->dev; + struct spi_master *master; + struct spi_device *spi_dev; + u32 irq; + int rv, id; + resource_size_t mapbase = pci_resource_start(pdev, MGB4_MGB4_BAR_ID); + + request_module("platform:xilinx_spi"); + + irq = xdma_get_user_irq(mgbdev->xdev, 14); + xdma_enable_user_irq(mgbdev->xdev, irq); + + spi_resources[0].parent = &pdev->resource[MGB4_MGB4_BAR_ID]; + spi_resources[0].start += mapbase; + spi_resources[0].end += mapbase; + spi_resources[1].start = irq; + spi_resources[1].end = irq; + + id = pci_dev_id(pdev); + mgbdev->spi_pdev = platform_device_register_resndata(dev, "xilinx_spi", + id, spi_resources, + ARRAY_SIZE(spi_resources), + &spi_platform_data, + sizeof(spi_platform_data)); + if (IS_ERR(mgbdev->spi_pdev)) { + dev_err(dev, "failed to register SPI device\n"); + return PTR_ERR(mgbdev->spi_pdev); + } + + master = get_spi_adap(mgbdev->spi_pdev); + if (!master) { + dev_err(dev, "failed to get SPI adapter\n"); + rv = -EINVAL; + goto err_pdev; + } + + snprintf(mgbdev->fw_part_name, sizeof(mgbdev->fw_part_name), + "mgb4-fw.%d", flashid); + mgbdev->partitions[0].name = mgbdev->fw_part_name; + mgbdev->partitions[0].size = 0x400000; + mgbdev->partitions[0].offset = 0x400000; + mgbdev->partitions[0].mask_flags = 0; + + snprintf(mgbdev->data_part_name, sizeof(mgbdev->data_part_name), + "mgb4-data.%d", flashid); + mgbdev->partitions[1].name = mgbdev->data_part_name; + mgbdev->partitions[1].size = 0x10000; + mgbdev->partitions[1].offset = 0xFF0000; + mgbdev->partitions[1].mask_flags = MTD_CAP_NORFLASH; + + snprintf(mgbdev->flash_name, sizeof(mgbdev->flash_name), + "mgb4-flash.%d", flashid); + mgbdev->flash_data.name = mgbdev->flash_name; + mgbdev->flash_data.parts = mgbdev->partitions; + mgbdev->flash_data.nr_parts = ARRAY_SIZE(mgbdev->partitions); + mgbdev->flash_data.type = "spi-nor"; + + spi_info.platform_data = &mgbdev->flash_data; + + spi_dev = spi_new_device(master, &spi_info); + put_device(&master->dev); + if (!spi_dev) { + dev_err(dev, "failed to create MTD device\n"); + rv = -EINVAL; + goto err_pdev; + } + + return 0; + +err_pdev: + platform_device_unregister(mgbdev->spi_pdev); + + return rv; +} + +static void free_spi(struct mgb4_dev *mgbdev) +{ + platform_device_unregister(mgbdev->spi_pdev); +} + +static int init_i2c(struct mgb4_dev *mgbdev) +{ + struct resource i2c_resources[] = { + { + .start = 0x200, + .end = 0x3ff, + .flags = IORESOURCE_MEM, + .name = "io-memory", + }, + { + .start = 15, + .end = 15, + .flags = IORESOURCE_IRQ, + .name = "irq", + }, + }; + struct pci_dev *pdev = mgbdev->pdev; + struct device *dev = &pdev->dev; + char clk_name[16]; + u32 irq; + int rv, id; + resource_size_t mapbase = pci_resource_start(pdev, MGB4_MGB4_BAR_ID); + + request_module("platform:xiic-i2c"); + + irq = xdma_get_user_irq(mgbdev->xdev, 15); + xdma_enable_user_irq(mgbdev->xdev, irq); + + i2c_resources[0].parent = &pdev->resource[MGB4_MGB4_BAR_ID]; + i2c_resources[0].start += mapbase; + i2c_resources[0].end += mapbase; + i2c_resources[1].start = irq; + i2c_resources[1].end = irq; + + id = pci_dev_id(pdev); + + /* create dummy clock required by the xiic-i2c adapter */ + snprintf(clk_name, sizeof(clk_name), "xiic-i2c.%d", id); + mgbdev->i2c_clk = clk_hw_register_fixed_rate(NULL, clk_name, NULL, + 0, 125000000); + if (IS_ERR(mgbdev->i2c_clk)) { + dev_err(dev, "failed to register I2C clock\n"); + return PTR_ERR(mgbdev->i2c_clk); + } + mgbdev->i2c_cl = clkdev_hw_create(mgbdev->i2c_clk, NULL, "xiic-i2c.%d", + id); + if (!mgbdev->i2c_cl) { + dev_err(dev, "failed to register I2C clockdev\n"); + rv = -ENOMEM; + goto err_clk; + } + + mgbdev->i2c_pdev = platform_device_register_resndata(dev, "xiic-i2c", + id, i2c_resources, + ARRAY_SIZE(i2c_resources), + NULL, 0); + if (IS_ERR(mgbdev->i2c_pdev)) { + dev_err(dev, "failed to register I2C device\n"); + rv = PTR_ERR(mgbdev->i2c_pdev); + goto err_clkdev; + } + + mgbdev->i2c_adap = get_i2c_adap(mgbdev->i2c_pdev); + if (!mgbdev->i2c_adap) { + dev_err(dev, "failed to get I2C adapter\n"); + rv = -EINVAL; + goto err_pdev; + } + + mutex_init(&mgbdev->i2c_lock); + + return 0; + +err_pdev: + platform_device_unregister(mgbdev->i2c_pdev); +err_clkdev: + clkdev_drop(mgbdev->i2c_cl); +err_clk: + clk_hw_unregister(mgbdev->i2c_clk); + + return rv; +} + +static void free_i2c(struct mgb4_dev *mgbdev) +{ + put_device(&mgbdev->i2c_adap->dev); + platform_device_unregister(mgbdev->i2c_pdev); + clkdev_drop(mgbdev->i2c_cl); + clk_hw_unregister(mgbdev->i2c_clk); +} + +static int get_serial_number(struct mgb4_dev *mgbdev) +{ + struct device *dev = &mgbdev->pdev->dev; + struct mtd_info *mtd; + size_t rs; + int rv; + + mgbdev->serial_number = 0; + + mtd = get_mtd_device_nm(mgbdev->data_part_name); + if (IS_ERR(mtd)) { + dev_warn(dev, "failed to get data MTD device\n"); + return -ENOENT; + } + rv = mtd_read(mtd, 0, sizeof(mgbdev->serial_number), &rs, + (u_char *)&mgbdev->serial_number); + put_mtd_device(mtd); + if (rv < 0 || rs != sizeof(mgbdev->serial_number)) { + dev_warn(dev, "error reading MTD device\n"); + return -EIO; + } + + return 0; +} + +static int get_module_version(struct mgb4_dev *mgbdev) +{ + struct device *dev = &mgbdev->pdev->dev; + struct mgb4_i2c_client extender; + s32 version; + u32 fw_version; + int rv; + + rv = mgb4_i2c_init(&extender, mgbdev->i2c_adap, &extender_info, 8); + if (rv < 0) { + dev_err(dev, "failed to create extender I2C device\n"); + return rv; + } + version = mgb4_i2c_read_byte(&extender, 0x00); + mgb4_i2c_free(&extender); + if (version < 0) { + dev_err(dev, "error reading module version\n"); + return -EIO; + } + + mgbdev->module_version = ~((u32)version) & 0xff; + if (!(MGB4_IS_FPDL3(mgbdev) || MGB4_IS_GMSL(mgbdev))) { + dev_err(dev, "unknown module type\n"); + return -EINVAL; + } + fw_version = mgb4_read_reg(&mgbdev->video, 0xC4); + if (fw_version >> 24 != mgbdev->module_version >> 4) { + dev_err(dev, "module/firmware type mismatch\n"); + return -EINVAL; + } + + dev_info(dev, "%s module detected\n", + MGB4_IS_FPDL3(mgbdev) ? "FPDL3" : "GMSL"); + + return 0; +} + +static int map_regs(struct pci_dev *pdev, struct resource *res, + struct mgb4_regs *regs) +{ + int rv; + resource_size_t mapbase = pci_resource_start(pdev, MGB4_MGB4_BAR_ID); + + res->start += mapbase; + res->end += mapbase; + + rv = mgb4_regs_map(res, regs); + if (rv < 0) { + dev_err(&pdev->dev, "failed to map %s registers\n", res->name); + return rv; + } + + return 0; +} + +static int init_xdma(struct mgb4_dev *mgbdev) +{ + struct xdma_platdata data; + struct resource res[2] = { 0 }; + struct dma_slave_map *map; + struct pci_dev *pdev = mgbdev->pdev; + struct device *dev = &pdev->dev; + int i; + + res[0].start = pci_resource_start(pdev, MGB4_XDMA_BAR_ID); + res[0].end = pci_resource_end(pdev, MGB4_XDMA_BAR_ID); + res[0].flags = IORESOURCE_MEM; + res[0].parent = &pdev->resource[MGB4_XDMA_BAR_ID]; + res[1].start = pci_irq_vector(pdev, 0); + res[1].end = res[1].start + MGB4_VIN_DEVICES + MGB4_VOUT_DEVICES + + MGB4_USER_IRQS - 1; + res[1].flags = IORESOURCE_IRQ; + + data.max_dma_channels = MGB4_VIN_DEVICES + MGB4_VOUT_DEVICES; + data.device_map = mgbdev->slave_map; + data.device_map_cnt = MGB4_VIN_DEVICES + MGB4_VOUT_DEVICES; + + for (i = 0; i < MGB4_VIN_DEVICES; i++) { + sprintf(mgbdev->channel_names[i], "c2h%d", i); + map = &data.device_map[i]; + map->slave = mgbdev->channel_names[i]; + map->devname = dev_name(dev); + map->param = XDMA_FILTER_PARAM(&c2h_chan_info); + } + for (i = 0; i < MGB4_VOUT_DEVICES; i++) { + sprintf(mgbdev->channel_names[i + MGB4_VIN_DEVICES], "h2c%d", i); + map = &data.device_map[i + MGB4_VIN_DEVICES]; + map->slave = mgbdev->channel_names[i + MGB4_VIN_DEVICES]; + map->devname = dev_name(dev); + map->param = XDMA_FILTER_PARAM(&h2c_chan_info); + } + + mgbdev->xdev = platform_device_register_resndata(dev, "xdma", + PLATFORM_DEVID_AUTO, res, + 2, &data, sizeof(data)); + if (IS_ERR(mgbdev->xdev)) { + dev_err(dev, "failed to register XDMA device\n"); + return PTR_ERR(mgbdev->xdev); + } + + return 0; +} + +static void free_xdma(struct mgb4_dev *mgbdev) +{ + platform_device_unregister(mgbdev->xdev); +} + +static int mgb4_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + int i, rv; + struct mgb4_dev *mgbdev; + struct resource video = { + .start = 0x0, + .end = 0x100, + .flags = IORESOURCE_MEM, + .name = "mgb4-video", + }; + struct resource cmt = { + .start = 0x1000, + .end = 0x1800, + .flags = IORESOURCE_MEM, + .name = "mgb4-cmt", + }; + int irqs = pci_msix_vec_count(pdev); + + mgbdev = kzalloc(sizeof(*mgbdev), GFP_KERNEL); + if (!mgbdev) + return -ENOMEM; + + mgbdev->pdev = pdev; + pci_set_drvdata(pdev, mgbdev); + + /* PCIe related stuff */ + rv = pci_enable_device(pdev); + if (rv) { + dev_err(&pdev->dev, "error enabling PCI device\n"); + goto err_mgbdev; + } + + rv = pcie_capability_set_word(pdev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_RELAX_EN); + if (rv) + dev_warn(&pdev->dev, "error enabling PCIe relaxed ordering\n"); + rv = pcie_capability_set_word(pdev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_EXT_TAG); + if (rv) + dev_warn(&pdev->dev, "error enabling PCIe extended tag field\n"); + rv = pcie_set_readrq(pdev, 512); + if (rv) + dev_warn(&pdev->dev, "error setting PCIe max. memory read size\n"); + pci_set_master(pdev); + + rv = pci_alloc_irq_vectors(pdev, irqs, irqs, PCI_IRQ_MSIX); + if (rv < 0) { + dev_err(&pdev->dev, "error allocating MSI-X IRQs\n"); + goto err_enable_pci; + } + + rv = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (rv) { + dev_err(&pdev->dev, "error setting DMA mask\n"); + goto err_enable_pci; + } + + /* DMA + IRQ engine */ + rv = init_xdma(mgbdev); + if (rv) + goto err_alloc_irq; + rv = mgb4_dma_channel_init(mgbdev); + if (rv) + goto err_dma_chan; + + /* mgb4 video registers */ + rv = map_regs(pdev, &video, &mgbdev->video); + if (rv < 0) + goto err_dma_chan; + /* mgb4 cmt registers */ + rv = map_regs(pdev, &cmt, &mgbdev->cmt); + if (rv < 0) + goto err_video_regs; + + /* SPI FLASH */ + rv = init_spi(mgbdev); + if (rv < 0) + goto err_cmt_regs; + + /* I2C controller */ + rv = init_i2c(mgbdev); + if (rv < 0) + goto err_spi; + + /* PCI card related sysfs attributes */ + rv = device_add_groups(&pdev->dev, mgb4_pci_groups); + if (rv < 0) + goto err_i2c; + +#if IS_REACHABLE(CONFIG_HWMON) + /* HWmon (card temperature) */ + mgbdev->hwmon_dev = hwmon_device_register_with_info(&pdev->dev, "mgb4", + mgbdev, + &temp_chip_info, + NULL); +#endif + +#ifdef CONFIG_DEBUG_FS + mgbdev->debugfs = debugfs_create_dir(dev_name(&pdev->dev), NULL); +#endif + + /* Get card serial number. On systems without MTD flash support we may + * get an error thus ignore the return value. An invalid serial number + * should not break anything... + */ + if (get_serial_number(mgbdev) < 0) + dev_warn(&pdev->dev, "error reading card serial number\n"); + + /* Get module type. If no valid module is found, skip the video device + * creation part but do not exit with error to allow flashing the card. + */ + rv = get_module_version(mgbdev); + if (rv < 0) + goto exit; + + /* Video input v4l2 devices */ + for (i = 0; i < MGB4_VIN_DEVICES; i++) + mgbdev->vin[i] = mgb4_vin_create(mgbdev, i); + + /* Video output v4l2 devices */ + for (i = 0; i < MGB4_VOUT_DEVICES; i++) + mgbdev->vout[i] = mgb4_vout_create(mgbdev, i); + + /* Triggers */ + mgbdev->indio_dev = mgb4_trigger_create(mgbdev); + +exit: + flashid++; + + return 0; + +err_i2c: + free_i2c(mgbdev); +err_spi: + free_spi(mgbdev); +err_cmt_regs: + mgb4_regs_free(&mgbdev->cmt); +err_video_regs: + mgb4_regs_free(&mgbdev->video); +err_dma_chan: + mgb4_dma_channel_free(mgbdev); + free_xdma(mgbdev); +err_alloc_irq: + pci_disable_msix(pdev); +err_enable_pci: + pci_disable_device(pdev); +err_mgbdev: + kfree(mgbdev); + + return rv; +} + +static void mgb4_remove(struct pci_dev *pdev) +{ + struct mgb4_dev *mgbdev = pci_get_drvdata(pdev); + int i; + +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(mgbdev->debugfs); +#endif +#if IS_REACHABLE(CONFIG_HWMON) + hwmon_device_unregister(mgbdev->hwmon_dev); +#endif + + if (mgbdev->indio_dev) + mgb4_trigger_free(mgbdev->indio_dev); + + for (i = 0; i < MGB4_VOUT_DEVICES; i++) + if (mgbdev->vout[i]) + mgb4_vout_free(mgbdev->vout[i]); + for (i = 0; i < MGB4_VIN_DEVICES; i++) + if (mgbdev->vin[i]) + mgb4_vin_free(mgbdev->vin[i]); + + device_remove_groups(&mgbdev->pdev->dev, mgb4_pci_groups); + free_spi(mgbdev); + free_i2c(mgbdev); + mgb4_regs_free(&mgbdev->video); + mgb4_regs_free(&mgbdev->cmt); + + mgb4_dma_channel_free(mgbdev); + free_xdma(mgbdev); + + pci_disable_msix(mgbdev->pdev); + pci_disable_device(mgbdev->pdev); + + kfree(mgbdev); +} + +static const struct pci_device_id mgb4_pci_ids[] = { + { PCI_DEVICE(0x1ed8, 0x0101), }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, mgb4_pci_ids); + +static struct pci_driver mgb4_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = mgb4_pci_ids, + .probe = mgb4_probe, + .remove = mgb4_remove, +}; + +module_pci_driver(mgb4_pci_driver); + +MODULE_AUTHOR("Digiteq Automotive s.r.o."); +MODULE_DESCRIPTION("Digiteq Automotive MGB4 Driver"); +MODULE_LICENSE("GPL"); +MODULE_SOFTDEP("pre: platform:xiic-i2c platform:xilinx_spi spi-nor"); diff --git a/drivers/media/pci/mgb4/mgb4_core.h b/drivers/media/pci/mgb4/mgb4_core.h new file mode 100644 index 0000000000000..2a946e46aec17 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_core.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma + */ + +#ifndef __MGB4_CORE_H__ +#define __MGB4_CORE_H__ + +#include +#include +#include +#include +#include "mgb4_regs.h" + +#define MGB4_VIN_DEVICES 2 +#define MGB4_VOUT_DEVICES 2 + +#define MGB4_MGB4_BAR_ID 0 +#define MGB4_XDMA_BAR_ID 1 + +#define MGB4_IS_GMSL(mgbdev) \ + ((mgbdev)->module_version >> 4 == 2) +#define MGB4_IS_FPDL3(mgbdev) \ + ((mgbdev)->module_version >> 4 == 1) + +struct mgb4_dma_channel { + struct dma_chan *chan; + struct completion req_compl; +}; + +struct mgb4_dev { + struct pci_dev *pdev; + struct platform_device *xdev; + struct mgb4_vin_dev *vin[MGB4_VIN_DEVICES]; + struct mgb4_vout_dev *vout[MGB4_VOUT_DEVICES]; + + struct mgb4_dma_channel c2h_chan[MGB4_VIN_DEVICES]; + struct mgb4_dma_channel h2c_chan[MGB4_VOUT_DEVICES]; + struct dma_slave_map slave_map[MGB4_VIN_DEVICES + MGB4_VOUT_DEVICES]; + + struct mgb4_regs video; + struct mgb4_regs cmt; + + struct clk_hw *i2c_clk; + struct clk_lookup *i2c_cl; + struct platform_device *i2c_pdev; + struct i2c_adapter *i2c_adap; + struct mutex i2c_lock; /* I2C bus access lock */ + + struct platform_device *spi_pdev; + struct flash_platform_data flash_data; + struct mtd_partition partitions[2]; + char flash_name[16]; + char fw_part_name[16]; + char data_part_name[16]; + char channel_names[MGB4_VIN_DEVICES + MGB4_VOUT_DEVICES][16]; + + struct iio_dev *indio_dev; +#if IS_REACHABLE(CONFIG_HWMON) + struct device *hwmon_dev; +#endif + + unsigned long io_reconfig; + + u8 module_version; + u32 serial_number; + +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs; +#endif +}; + +#endif diff --git a/drivers/media/pci/mgb4/mgb4_dma.c b/drivers/media/pci/mgb4/mgb4_dma.c new file mode 100644 index 0000000000000..cae888e6504b0 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_dma.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 Digiteq Automotive + * author: Martin Tuma + * + * This module handles the DMA transfers. A standard dmaengine API as provided + * by the XDMA module is used. + */ + +#include +#include +#include "mgb4_core.h" +#include "mgb4_dma.h" + +static void chan_irq(void *param) +{ + struct mgb4_dma_channel *chan = param; + + complete(&chan->req_compl); +} + +int mgb4_dma_transfer(struct mgb4_dev *mgbdev, u32 channel, bool write, + u64 paddr, struct sg_table *sgt) +{ + struct dma_slave_config cfg; + struct mgb4_dma_channel *chan; + struct dma_async_tx_descriptor *tx; + struct pci_dev *pdev = mgbdev->pdev; + int ret; + + memset(&cfg, 0, sizeof(cfg)); + + if (write) { + cfg.direction = DMA_MEM_TO_DEV; + cfg.dst_addr = paddr; + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + chan = &mgbdev->h2c_chan[channel]; + } else { + cfg.direction = DMA_DEV_TO_MEM; + cfg.src_addr = paddr; + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + chan = &mgbdev->c2h_chan[channel]; + } + + ret = dmaengine_slave_config(chan->chan, &cfg); + if (ret) { + dev_err(&pdev->dev, "failed to config dma: %d\n", ret); + return ret; + } + + tx = dmaengine_prep_slave_sg(chan->chan, sgt->sgl, sgt->nents, + cfg.direction, 0); + if (!tx) { + dev_err(&pdev->dev, "failed to prep slave sg\n"); + return -EIO; + } + + tx->callback = chan_irq; + tx->callback_param = chan; + + ret = dma_submit_error(dmaengine_submit(tx)); + if (ret) { + dev_err(&pdev->dev, "failed to submit sg\n"); + return -EIO; + } + + dma_async_issue_pending(chan->chan); + + if (!wait_for_completion_timeout(&chan->req_compl, + msecs_to_jiffies(10000))) { + dev_err(&pdev->dev, "dma timeout\n"); + dmaengine_terminate_sync(chan->chan); + return -EIO; + } + + return 0; +} + +int mgb4_dma_channel_init(struct mgb4_dev *mgbdev) +{ + int i, ret; + char name[16]; + struct pci_dev *pdev = mgbdev->pdev; + + for (i = 0; i < MGB4_VIN_DEVICES; i++) { + sprintf(name, "c2h%d", i); + mgbdev->c2h_chan[i].chan = dma_request_chan(&pdev->dev, name); + if (IS_ERR(mgbdev->c2h_chan[i].chan)) { + dev_err(&pdev->dev, "failed to initialize %s", name); + ret = PTR_ERR(mgbdev->c2h_chan[i].chan); + mgbdev->c2h_chan[i].chan = NULL; + return ret; + } + init_completion(&mgbdev->c2h_chan[i].req_compl); + } + for (i = 0; i < MGB4_VOUT_DEVICES; i++) { + sprintf(name, "h2c%d", i); + mgbdev->h2c_chan[i].chan = dma_request_chan(&pdev->dev, name); + if (IS_ERR(mgbdev->h2c_chan[i].chan)) { + dev_err(&pdev->dev, "failed to initialize %s", name); + ret = PTR_ERR(mgbdev->h2c_chan[i].chan); + mgbdev->h2c_chan[i].chan = NULL; + return ret; + } + init_completion(&mgbdev->h2c_chan[i].req_compl); + } + + return 0; +} + +void mgb4_dma_channel_free(struct mgb4_dev *mgbdev) +{ + int i; + + for (i = 0; i < MGB4_VIN_DEVICES; i++) { + if (mgbdev->c2h_chan[i].chan) + dma_release_channel(mgbdev->c2h_chan[i].chan); + } + for (i = 0; i < MGB4_VOUT_DEVICES; i++) { + if (mgbdev->h2c_chan[i].chan) + dma_release_channel(mgbdev->h2c_chan[i].chan); + } +} diff --git a/drivers/media/pci/mgb4/mgb4_dma.h b/drivers/media/pci/mgb4/mgb4_dma.h new file mode 100644 index 0000000000000..4ebc2b1ce9b7d --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_dma.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma + */ + +#ifndef __MGB4_DMA_H__ +#define __MGB4_DMA_H__ + +#include "mgb4_core.h" + +int mgb4_dma_channel_init(struct mgb4_dev *mgbdev); +void mgb4_dma_channel_free(struct mgb4_dev *mgbdev); + +int mgb4_dma_transfer(struct mgb4_dev *mgbdev, u32 channel, bool write, + u64 paddr, struct sg_table *sgt); + +#endif diff --git a/drivers/media/pci/mgb4/mgb4_i2c.c b/drivers/media/pci/mgb4/mgb4_i2c.c new file mode 100644 index 0000000000000..2697b67e290e1 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_i2c.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma + * + * The i2c module unifies the I2C access to the serializes/deserializes. The I2C + * chips on the GMSL module use 16b addressing, the FPDL3 chips use standard + * 8b addressing. + */ + +#include "mgb4_i2c.h" + +static int read_r16(struct i2c_client *client, u16 reg, u8 *val, int len) +{ + int ret; + u8 buf[2]; + struct i2c_msg msg[2] = { + { + .addr = client->addr, + .flags = 0, + .len = 2, + .buf = buf, + }, { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = val, + } + }; + + buf[0] = (reg >> 8) & 0xff; + buf[1] = (reg >> 0) & 0xff; + + ret = i2c_transfer(client->adapter, msg, 2); + if (ret < 0) + return ret; + else if (ret != 2) + return -EREMOTEIO; + else + return 0; +} + +static int write_r16(struct i2c_client *client, u16 reg, const u8 *val, int len) +{ + int ret; + u8 buf[4]; + struct i2c_msg msg[1] = { + { + .addr = client->addr, + .flags = 0, + .len = 2 + len, + .buf = buf, + } + }; + + if (2 + len > sizeof(buf)) + return -EINVAL; + + buf[0] = (reg >> 8) & 0xff; + buf[1] = (reg >> 0) & 0xff; + memcpy(&buf[2], val, len); + + ret = i2c_transfer(client->adapter, msg, 1); + if (ret < 0) + return ret; + else if (ret != 1) + return -EREMOTEIO; + else + return 0; +} + +int mgb4_i2c_init(struct mgb4_i2c_client *client, struct i2c_adapter *adap, + struct i2c_board_info const *info, int addr_size) +{ + client->client = i2c_new_client_device(adap, info); + if (IS_ERR(client->client)) + return PTR_ERR(client->client); + + client->addr_size = addr_size; + + return 0; +} + +void mgb4_i2c_free(struct mgb4_i2c_client *client) +{ + i2c_unregister_device(client->client); +} + +s32 mgb4_i2c_read_byte(struct mgb4_i2c_client *client, u16 reg) +{ + int ret; + u8 b; + + if (client->addr_size == 8) + return i2c_smbus_read_byte_data(client->client, reg); + + ret = read_r16(client->client, reg, &b, 1); + if (ret < 0) + return ret; + + return (s32)b; +} + +s32 mgb4_i2c_write_byte(struct mgb4_i2c_client *client, u16 reg, u8 val) +{ + if (client->addr_size == 8) + return i2c_smbus_write_byte_data(client->client, reg, val); + else + return write_r16(client->client, reg, &val, 1); +} + +s32 mgb4_i2c_mask_byte(struct mgb4_i2c_client *client, u16 reg, u8 mask, u8 val) +{ + s32 ret; + + if (mask != 0xFF) { + ret = mgb4_i2c_read_byte(client, reg); + if (ret < 0) + return ret; + val |= (u8)ret & ~mask; + } + + return mgb4_i2c_write_byte(client, reg, val); +} + +int mgb4_i2c_configure(struct mgb4_i2c_client *client, + const struct mgb4_i2c_kv *values, size_t count) +{ + size_t i; + s32 res; + + for (i = 0; i < count; i++) { + res = mgb4_i2c_mask_byte(client, values[i].reg, values[i].mask, + values[i].val); + if (res < 0) + return res; + } + + return 0; +} diff --git a/drivers/media/pci/mgb4/mgb4_i2c.h b/drivers/media/pci/mgb4/mgb4_i2c.h new file mode 100644 index 0000000000000..fac6a16344742 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_i2c.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma + */ + +#ifndef __MGB4_I2C_H__ +#define __MGB4_I2C_H__ + +#include + +struct mgb4_i2c_client { + struct i2c_client *client; + int addr_size; +}; + +struct mgb4_i2c_kv { + u16 reg; + u8 mask; + u8 val; +}; + +int mgb4_i2c_init(struct mgb4_i2c_client *client, struct i2c_adapter *adap, + struct i2c_board_info const *info, int addr_size); +void mgb4_i2c_free(struct mgb4_i2c_client *client); + +s32 mgb4_i2c_read_byte(struct mgb4_i2c_client *client, u16 reg); +s32 mgb4_i2c_write_byte(struct mgb4_i2c_client *client, u16 reg, u8 val); +s32 mgb4_i2c_mask_byte(struct mgb4_i2c_client *client, u16 reg, u8 mask, + u8 val); + +int mgb4_i2c_configure(struct mgb4_i2c_client *client, + const struct mgb4_i2c_kv *values, size_t count); + +#endif diff --git a/drivers/media/pci/mgb4/mgb4_io.h b/drivers/media/pci/mgb4/mgb4_io.h new file mode 100644 index 0000000000000..8698db1be4a9e --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_io.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021-2022 Digiteq Automotive + * author: Martin Tuma + */ + +#ifndef __MGB4_IO_H__ +#define __MGB4_IO_H__ + +#include + +#define MGB4_DEFAULT_WIDTH 1280 +#define MGB4_DEFAULT_HEIGHT 640 +#define MGB4_DEFAULT_PERIOD (125000000 / 60) + +/* Register access error indication */ +#define MGB4_ERR_NO_REG 0xFFFFFFFE +/* Frame buffer addresses greater than 0xFFFFFFFA indicate HW errors */ +#define MGB4_ERR_QUEUE_TIMEOUT 0xFFFFFFFD +#define MGB4_ERR_QUEUE_EMPTY 0xFFFFFFFC +#define MGB4_ERR_QUEUE_FULL 0xFFFFFFFB + +struct mgb4_frame_buffer { + struct vb2_v4l2_buffer vb; + struct list_head list; +}; + +static inline struct mgb4_frame_buffer *to_frame_buffer(struct vb2_v4l2_buffer *vbuf) +{ + return container_of(vbuf, struct mgb4_frame_buffer, vb); +} + +#endif diff --git a/drivers/media/pci/mgb4/mgb4_regs.c b/drivers/media/pci/mgb4/mgb4_regs.c new file mode 100644 index 0000000000000..53d4e4503a74c --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_regs.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 Digiteq Automotive + * author: Martin Tuma + */ + +#include +#include "mgb4_regs.h" + +int mgb4_regs_map(struct resource *res, struct mgb4_regs *regs) +{ + regs->mapbase = res->start; + regs->mapsize = res->end - res->start; + + if (!request_mem_region(regs->mapbase, regs->mapsize, res->name)) + return -EINVAL; + regs->membase = ioremap(regs->mapbase, regs->mapsize); + if (!regs->membase) { + release_mem_region(regs->mapbase, regs->mapsize); + return -EINVAL; + } + + return 0; +} + +void mgb4_regs_free(struct mgb4_regs *regs) +{ + iounmap(regs->membase); + release_mem_region(regs->mapbase, regs->mapsize); +} diff --git a/drivers/media/pci/mgb4/mgb4_regs.h b/drivers/media/pci/mgb4/mgb4_regs.h new file mode 100644 index 0000000000000..c451808907308 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_regs.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021-2022 Digiteq Automotive + * author: Martin Tuma + */ + +#ifndef __MGB4_REGS_H__ +#define __MGB4_REGS_H__ + +#include + +struct mgb4_regs { + resource_size_t mapbase; + resource_size_t mapsize; + void __iomem *membase; +}; + +#define mgb4_write_reg(regs, offset, val) \ + iowrite32(val, (regs)->membase + (offset)) +#define mgb4_read_reg(regs, offset) \ + ioread32((regs)->membase + (offset)) + +static inline void mgb4_mask_reg(struct mgb4_regs *regs, u32 reg, u32 mask, + u32 val) +{ + u32 ret = mgb4_read_reg(regs, reg); + + val |= ret & ~mask; + mgb4_write_reg(regs, reg, val); +} + +int mgb4_regs_map(struct resource *res, struct mgb4_regs *regs); +void mgb4_regs_free(struct mgb4_regs *regs); + +#endif diff --git a/drivers/media/pci/mgb4/mgb4_sysfs.h b/drivers/media/pci/mgb4/mgb4_sysfs.h new file mode 100644 index 0000000000000..017d82c0624e9 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_sysfs.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021-2022 Digiteq Automotive + * author: Martin Tuma + */ + +#ifndef __MGB4_SYSFS_H__ +#define __MGB4_SYSFS_H__ + +#include + +extern struct attribute *mgb4_pci_attrs[]; +extern struct attribute *mgb4_fpdl3_in_attrs[]; +extern struct attribute *mgb4_gmsl_in_attrs[]; +extern struct attribute *mgb4_fpdl3_out_attrs[]; +extern struct attribute *mgb4_gmsl_out_attrs[]; + +#endif diff --git a/drivers/media/pci/mgb4/mgb4_sysfs_in.c b/drivers/media/pci/mgb4/mgb4_sysfs_in.c new file mode 100644 index 0000000000000..0ba66a2cf1453 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_sysfs_in.c @@ -0,0 +1,772 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma + * + * This module handles all the sysfs info/configuration that is related to the + * v4l2 input devices. + */ + +#include +#include "mgb4_core.h" +#include "mgb4_i2c.h" +#include "mgb4_vin.h" +#include "mgb4_cmt.h" +#include "mgb4_sysfs.h" + +/* Common for both FPDL3 and GMSL */ + +static ssize_t input_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + + return sprintf(buf, "%d\n", vindev->config->id); +} + +static ssize_t oldi_lane_width_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + struct mgb4_dev *mgbdev = vindev->mgbdev; + u16 i2c_reg; + u8 i2c_mask, i2c_single_val, i2c_dual_val; + u32 config; + int ret; + + i2c_reg = MGB4_IS_GMSL(mgbdev) ? 0x1CE : 0x49; + i2c_mask = MGB4_IS_GMSL(mgbdev) ? 0x0E : 0x03; + i2c_single_val = MGB4_IS_GMSL(mgbdev) ? 0x00 : 0x02; + i2c_dual_val = MGB4_IS_GMSL(mgbdev) ? 0x0E : 0x00; + + mutex_lock(&mgbdev->i2c_lock); + ret = mgb4_i2c_read_byte(&vindev->deser, i2c_reg); + mutex_unlock(&mgbdev->i2c_lock); + if (ret < 0) + return -EIO; + + config = mgb4_read_reg(&mgbdev->video, vindev->config->regs.config); + + if (((config & (1U << 9)) && ((ret & i2c_mask) != i2c_dual_val)) || + (!(config & (1U << 9)) && ((ret & i2c_mask) != i2c_single_val))) { + dev_err(dev, "I2C/FPGA register value mismatch\n"); + return -EINVAL; + } + + return sprintf(buf, "%s\n", config & (1U << 9) ? "1" : "0"); +} + +/* + * OLDI lane width change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t oldi_lane_width_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + struct mgb4_dev *mgbdev = vindev->mgbdev; + u32 fpga_data; + u16 i2c_reg; + u8 i2c_mask, i2c_data; + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + switch (val) { + case 0: /* single */ + fpga_data = 0; + i2c_data = MGB4_IS_GMSL(mgbdev) ? 0x00 : 0x02; + break; + case 1: /* dual */ + fpga_data = 1U << 9; + i2c_data = MGB4_IS_GMSL(mgbdev) ? 0x0E : 0x00; + break; + default: + return -EINVAL; + } + + i2c_reg = MGB4_IS_GMSL(mgbdev) ? 0x1CE : 0x49; + i2c_mask = MGB4_IS_GMSL(mgbdev) ? 0x0E : 0x03; + + mutex_lock(&mgbdev->i2c_lock); + ret = mgb4_i2c_mask_byte(&vindev->deser, i2c_reg, i2c_mask, i2c_data); + mutex_unlock(&mgbdev->i2c_lock); + if (ret < 0) + return -EIO; + mgb4_mask_reg(&mgbdev->video, vindev->config->regs.config, 1U << 9, + fpga_data); + if (MGB4_IS_GMSL(mgbdev)) { + /* reset input link */ + mutex_lock(&mgbdev->i2c_lock); + ret = mgb4_i2c_mask_byte(&vindev->deser, 0x10, 1U << 5, 1U << 5); + mutex_unlock(&mgbdev->i2c_lock); + if (ret < 0) + return -EIO; + } + + return count; +} + +static ssize_t color_mapping_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 config = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.config); + + return sprintf(buf, "%s\n", config & (1U << 8) ? "0" : "1"); +} + +/* + * Color mapping change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t color_mapping_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 fpga_data; + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + switch (val) { + case 0: /* OLDI/JEIDA */ + fpga_data = (1U << 8); + break; + case 1: /* SPWG/VESA */ + fpga_data = 0; + break; + default: + return -EINVAL; + } + + mgb4_mask_reg(&vindev->mgbdev->video, vindev->config->regs.config, + 1U << 8, fpga_data); + + return count; +} + +static ssize_t link_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 status = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.status); + + return sprintf(buf, "%s\n", status & (1U << 2) ? "1" : "0"); +} + +static ssize_t stream_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 status = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.status); + + return sprintf(buf, "%s\n", ((status & (1 << 14)) && + (status & (1 << 2)) && (status & (3 << 9))) ? "1" : "0"); +} + +static ssize_t video_width_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 config = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.resolution); + + return sprintf(buf, "%u\n", config >> 16); +} + +static ssize_t video_height_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 config = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.resolution); + + return sprintf(buf, "%u\n", config & 0xFFFF); +} + +static ssize_t hsync_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 status = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.status); + u32 res; + + if (!(status & (1U << 11))) + res = 0x02; // not available + else if (status & (1U << 12)) + res = 0x01; // active high + else + res = 0x00; // active low + + return sprintf(buf, "%u\n", res); +} + +static ssize_t vsync_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 status = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.status); + u32 res; + + if (!(status & (1U << 11))) + res = 0x02; // not available + else if (status & (1U << 13)) + res = 0x01; // active high + else + res = 0x00; // active low + + return sprintf(buf, "%u\n", res); +} + +static ssize_t hsync_gap_length_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 sync = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.sync); + + return sprintf(buf, "%u\n", sync >> 16); +} + +/* + * HSYNC gap length change is expected to be called on live streams. Video + * device locking/queue check is not needed. + */ +static ssize_t hsync_gap_length_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 0xFFFF) + return -EINVAL; + + mgb4_mask_reg(&vindev->mgbdev->video, vindev->config->regs.sync, + 0xFFFF0000, val << 16); + + return count; +} + +static ssize_t vsync_gap_length_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 sync = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.sync); + + return sprintf(buf, "%u\n", sync & 0xFFFF); +} + +/* + * VSYNC gap length change is expected to be called on live streams. Video + * device locking/queue check is not needed. + */ +static ssize_t vsync_gap_length_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 0xFFFF) + return -EINVAL; + + mgb4_mask_reg(&vindev->mgbdev->video, vindev->config->regs.sync, 0xFFFF, + val); + + return count; +} + +static ssize_t pclk_frequency_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 freq = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.pclk); + + return sprintf(buf, "%u\n", freq); +} + +static ssize_t hsync_width_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.signal); + + return sprintf(buf, "%u\n", (sig & 0x00FF0000) >> 16); +} + +static ssize_t vsync_width_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.signal2); + + return sprintf(buf, "%u\n", (sig & 0x00FF0000) >> 16); +} + +static ssize_t hback_porch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.signal); + + return sprintf(buf, "%u\n", (sig & 0x0000FF00) >> 8); +} + +static ssize_t hfront_porch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.signal); + + return sprintf(buf, "%u\n", (sig & 0x000000FF)); +} + +static ssize_t vback_porch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.signal2); + + return sprintf(buf, "%u\n", (sig & 0x0000FF00) >> 8); +} + +static ssize_t vfront_porch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.signal2); + + return sprintf(buf, "%u\n", (sig & 0x000000FF)); +} + +static ssize_t frequency_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + + return sprintf(buf, "%d\n", vindev->freq_range); +} + +static ssize_t frequency_range_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 1) + return -EINVAL; + + mutex_lock(vindev->vdev.lock); + if (vb2_is_busy(vindev->vdev.queue)) { + mutex_unlock(vindev->vdev.lock); + return -EBUSY; + } + + mgb4_cmt_set_vin_freq_range(vindev, val); + vindev->freq_range = val; + + mutex_unlock(vindev->vdev.lock); + + return count; +} + +/* FPDL3 only */ + +static ssize_t fpdl3_input_width_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + s32 ret; + + mutex_lock(&vindev->mgbdev->i2c_lock); + ret = mgb4_i2c_read_byte(&vindev->deser, 0x34); + mutex_unlock(&vindev->mgbdev->i2c_lock); + if (ret < 0) + return -EIO; + + switch ((u8)ret & 0x18) { + case 0: + return sprintf(buf, "0\n"); + case 0x10: + return sprintf(buf, "1\n"); + case 0x08: + return sprintf(buf, "2\n"); + default: + return -EINVAL; + } +} + +/* + * FPD-Link width change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t fpdl3_input_width_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u8 i2c_data; + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + switch (val) { + case 0: /* auto */ + i2c_data = 0x00; + break; + case 1: /* single */ + i2c_data = 0x10; + break; + case 2: /* dual */ + i2c_data = 0x08; + break; + default: + return -EINVAL; + } + + mutex_lock(&vindev->mgbdev->i2c_lock); + ret = mgb4_i2c_mask_byte(&vindev->deser, 0x34, 0x18, i2c_data); + mutex_unlock(&vindev->mgbdev->i2c_lock); + if (ret < 0) + return -EIO; + + return count; +} + +/* GMSL only */ + +static ssize_t gmsl_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + s32 r1, r300, r3; + + mutex_lock(&vindev->mgbdev->i2c_lock); + r1 = mgb4_i2c_read_byte(&vindev->deser, 0x01); + r300 = mgb4_i2c_read_byte(&vindev->deser, 0x300); + r3 = mgb4_i2c_read_byte(&vindev->deser, 0x03); + mutex_unlock(&vindev->mgbdev->i2c_lock); + if (r1 < 0 || r300 < 0 || r3 < 0) + return -EIO; + + if ((r1 & 0x03) == 0x03 && (r300 & 0x0C) == 0x0C && (r3 & 0xC0) == 0xC0) + return sprintf(buf, "0\n"); + else if ((r1 & 0x03) == 0x02 && (r300 & 0x0C) == 0x08 && (r3 & 0xC0) == 0x00) + return sprintf(buf, "1\n"); + else if ((r1 & 0x03) == 0x01 && (r300 & 0x0C) == 0x04 && (r3 & 0xC0) == 0x00) + return sprintf(buf, "2\n"); + else if ((r1 & 0x03) == 0x00 && (r300 & 0x0C) == 0x00 && (r3 & 0xC0) == 0x00) + return sprintf(buf, "3\n"); + else + return -EINVAL; +} + +/* + * GMSL mode change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t gmsl_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + static const struct mgb4_i2c_kv G12[] = { + {0x01, 0x03, 0x03}, {0x300, 0x0C, 0x0C}, {0x03, 0xC0, 0xC0}}; + static const struct mgb4_i2c_kv G6[] = { + {0x01, 0x03, 0x02}, {0x300, 0x0C, 0x08}, {0x03, 0xC0, 0x00}}; + static const struct mgb4_i2c_kv G3[] = { + {0x01, 0x03, 0x01}, {0x300, 0x0C, 0x04}, {0x03, 0xC0, 0x00}}; + static const struct mgb4_i2c_kv G1[] = { + {0x01, 0x03, 0x00}, {0x300, 0x0C, 0x00}, {0x03, 0xC0, 0x00}}; + static const struct mgb4_i2c_kv reset[] = { + {0x10, 1U << 5, 1U << 5}, {0x300, 1U << 6, 1U << 6}}; + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + const struct mgb4_i2c_kv *values; + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + switch (val) { + case 0: /* 12Gb/s */ + values = G12; + break; + case 1: /* 6Gb/s */ + values = G6; + break; + case 2: /* 3Gb/s */ + values = G3; + break; + case 3: /* 1.5Gb/s */ + values = G1; + break; + default: + return -EINVAL; + } + + mutex_lock(&vindev->mgbdev->i2c_lock); + ret = mgb4_i2c_configure(&vindev->deser, values, 3); + ret |= mgb4_i2c_configure(&vindev->deser, reset, 2); + mutex_unlock(&vindev->mgbdev->i2c_lock); + if (ret < 0) + return -EIO; + + return count; +} + +static ssize_t gmsl_stream_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + s32 ret; + + mutex_lock(&vindev->mgbdev->i2c_lock); + ret = mgb4_i2c_read_byte(&vindev->deser, 0xA0); + mutex_unlock(&vindev->mgbdev->i2c_lock); + if (ret < 0) + return -EIO; + + return sprintf(buf, "%d\n", ret & 0x03); +} + +static ssize_t gmsl_stream_id_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 3) + return -EINVAL; + + mutex_lock(vindev->vdev.lock); + if (vb2_is_busy(vindev->vdev.queue)) { + mutex_unlock(vindev->vdev.lock); + return -EBUSY; + } + + mutex_lock(&vindev->mgbdev->i2c_lock); + ret = mgb4_i2c_mask_byte(&vindev->deser, 0xA0, 0x03, (u8)val); + mutex_unlock(&vindev->mgbdev->i2c_lock); + + mutex_unlock(vindev->vdev.lock); + + return (ret < 0) ? -EIO : count; +} + +static ssize_t gmsl_fec_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + s32 r3e0, r308; + + mutex_lock(&vindev->mgbdev->i2c_lock); + r3e0 = mgb4_i2c_read_byte(&vindev->deser, 0x3E0); + r308 = mgb4_i2c_read_byte(&vindev->deser, 0x308); + mutex_unlock(&vindev->mgbdev->i2c_lock); + if (r3e0 < 0 || r308 < 0) + return -EIO; + + if ((r3e0 & 0x07) == 0x00 && (r308 & 0x01) == 0x00) + return sprintf(buf, "0\n"); + else if ((r3e0 & 0x07) == 0x07 && (r308 & 0x01) == 0x01) + return sprintf(buf, "1\n"); + else + return -EINVAL; +} + +/* + * GMSL FEC change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t gmsl_fec_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + static const struct mgb4_i2c_kv enable[] = { + {0x3E0, 0x07, 0x07}, {0x308, 0x01, 0x01}}; + static const struct mgb4_i2c_kv disable[] = { + {0x3E0, 0x07, 0x00}, {0x308, 0x01, 0x00}}; + static const struct mgb4_i2c_kv reset[] = { + {0x10, 1U << 5, 1U << 5}, {0x300, 1U << 6, 1U << 6}}; + const struct mgb4_i2c_kv *values; + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + switch (val) { + case 0: /* disabled */ + values = disable; + break; + case 1: /* enabled */ + values = enable; + break; + default: + return -EINVAL; + } + + mutex_lock(&vindev->mgbdev->i2c_lock); + ret = mgb4_i2c_configure(&vindev->deser, values, 2); + ret |= mgb4_i2c_configure(&vindev->deser, reset, 2); + mutex_unlock(&vindev->mgbdev->i2c_lock); + if (ret < 0) + return -EIO; + + return count; +} + +static DEVICE_ATTR_RO(input_id); +static DEVICE_ATTR_RW(oldi_lane_width); +static DEVICE_ATTR_RW(color_mapping); +static DEVICE_ATTR_RO(link_status); +static DEVICE_ATTR_RO(stream_status); +static DEVICE_ATTR_RO(video_width); +static DEVICE_ATTR_RO(video_height); +static DEVICE_ATTR_RO(hsync_status); +static DEVICE_ATTR_RO(vsync_status); +static DEVICE_ATTR_RW(hsync_gap_length); +static DEVICE_ATTR_RW(vsync_gap_length); +static DEVICE_ATTR_RO(pclk_frequency); +static DEVICE_ATTR_RO(hsync_width); +static DEVICE_ATTR_RO(vsync_width); +static DEVICE_ATTR_RO(hback_porch); +static DEVICE_ATTR_RO(hfront_porch); +static DEVICE_ATTR_RO(vback_porch); +static DEVICE_ATTR_RO(vfront_porch); +static DEVICE_ATTR_RW(frequency_range); + +static DEVICE_ATTR_RW(fpdl3_input_width); + +static DEVICE_ATTR_RW(gmsl_mode); +static DEVICE_ATTR_RW(gmsl_stream_id); +static DEVICE_ATTR_RW(gmsl_fec); + +struct attribute *mgb4_fpdl3_in_attrs[] = { + &dev_attr_input_id.attr, + &dev_attr_link_status.attr, + &dev_attr_stream_status.attr, + &dev_attr_video_width.attr, + &dev_attr_video_height.attr, + &dev_attr_hsync_status.attr, + &dev_attr_vsync_status.attr, + &dev_attr_oldi_lane_width.attr, + &dev_attr_color_mapping.attr, + &dev_attr_hsync_gap_length.attr, + &dev_attr_vsync_gap_length.attr, + &dev_attr_pclk_frequency.attr, + &dev_attr_hsync_width.attr, + &dev_attr_vsync_width.attr, + &dev_attr_hback_porch.attr, + &dev_attr_hfront_porch.attr, + &dev_attr_vback_porch.attr, + &dev_attr_vfront_porch.attr, + &dev_attr_frequency_range.attr, + &dev_attr_fpdl3_input_width.attr, + NULL +}; + +struct attribute *mgb4_gmsl_in_attrs[] = { + &dev_attr_input_id.attr, + &dev_attr_link_status.attr, + &dev_attr_stream_status.attr, + &dev_attr_video_width.attr, + &dev_attr_video_height.attr, + &dev_attr_hsync_status.attr, + &dev_attr_vsync_status.attr, + &dev_attr_oldi_lane_width.attr, + &dev_attr_color_mapping.attr, + &dev_attr_hsync_gap_length.attr, + &dev_attr_vsync_gap_length.attr, + &dev_attr_pclk_frequency.attr, + &dev_attr_hsync_width.attr, + &dev_attr_vsync_width.attr, + &dev_attr_hback_porch.attr, + &dev_attr_hfront_porch.attr, + &dev_attr_vback_porch.attr, + &dev_attr_vfront_porch.attr, + &dev_attr_frequency_range.attr, + &dev_attr_gmsl_mode.attr, + &dev_attr_gmsl_stream_id.attr, + &dev_attr_gmsl_fec.attr, + NULL +}; diff --git a/drivers/media/pci/mgb4/mgb4_sysfs_out.c b/drivers/media/pci/mgb4/mgb4_sysfs_out.c new file mode 100644 index 0000000000000..23a9aabf3915d --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_sysfs_out.c @@ -0,0 +1,737 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma + * + * This module handles all the sysfs info/configuration that is related to the + * v4l2 output devices. + */ + +#include +#include "mgb4_core.h" +#include "mgb4_i2c.h" +#include "mgb4_vout.h" +#include "mgb4_vin.h" +#include "mgb4_cmt.h" +#include "mgb4_sysfs.h" + +static int loopin_cnt(struct mgb4_vin_dev *vindev) +{ + struct mgb4_vout_dev *voutdev; + u32 config; + int i, cnt = 0; + + for (i = 0; i < MGB4_VOUT_DEVICES; i++) { + voutdev = vindev->mgbdev->vout[i]; + if (!voutdev) + continue; + + config = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.config); + if ((config & 0xc) >> 2 == vindev->config->id) + cnt++; + } + + return cnt; +} + +static bool is_busy(struct video_device *dev) +{ + bool ret; + + mutex_lock(dev->lock); + ret = vb2_is_busy(dev->queue); + mutex_unlock(dev->lock); + + return ret; +} + +/* Common for both FPDL3 and GMSL */ + +static ssize_t output_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + + return sprintf(buf, "%d\n", voutdev->config->id); +} + +static ssize_t video_source_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 config = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.config); + + return sprintf(buf, "%u\n", (config & 0xc) >> 2); +} + +/* + * Video source change may affect the buffer queue of ANY video input/output on + * the card thus if any of the inputs/outputs is in use, we do not allow + * the change. + * + * As we do not want to lock all the video devices at the same time, a two-stage + * locking strategy is used. In addition to the video device locking there is + * a global (PCI device) variable "io_reconfig" atomically checked/set when + * the reconfiguration is running. All the video devices check the variable in + * their queue_setup() functions and do not allow to start the queue when + * the reconfiguration has started. + */ +static ssize_t video_source_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + struct mgb4_dev *mgbdev = voutdev->mgbdev; + struct mgb4_vin_dev *loopin_new = NULL, *loopin_old = NULL; + unsigned long val; + ssize_t ret; + u32 config; + int i; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 3) + return -EINVAL; + + if (test_and_set_bit(0, &mgbdev->io_reconfig)) + return -EBUSY; + + ret = -EBUSY; + for (i = 0; i < MGB4_VIN_DEVICES; i++) + if (mgbdev->vin[i] && is_busy(&mgbdev->vin[i]->vdev)) + goto end; + for (i = 0; i < MGB4_VOUT_DEVICES; i++) + if (mgbdev->vout[i] && is_busy(&mgbdev->vout[i]->vdev)) + goto end; + + config = mgb4_read_reg(&mgbdev->video, voutdev->config->regs.config); + + if (((config & 0xc) >> 2) < MGB4_VIN_DEVICES) + loopin_old = mgbdev->vin[(config & 0xc) >> 2]; + if (val < MGB4_VIN_DEVICES) + loopin_new = mgbdev->vin[val]; + if (loopin_old && loopin_cnt(loopin_old) == 1) + mgb4_mask_reg(&mgbdev->video, loopin_old->config->regs.config, + 0x2, 0x0); + if (loopin_new) + mgb4_mask_reg(&mgbdev->video, loopin_new->config->regs.config, + 0x2, 0x2); + + if (val == voutdev->config->id + MGB4_VIN_DEVICES) + mgb4_write_reg(&mgbdev->video, voutdev->config->regs.config, + config & ~(1 << 1)); + else + mgb4_write_reg(&mgbdev->video, voutdev->config->regs.config, + config | (1U << 1)); + + mgb4_mask_reg(&mgbdev->video, voutdev->config->regs.config, 0xc, + val << 2); + + ret = count; +end: + clear_bit(0, &mgbdev->io_reconfig); + + return ret; +} + +static ssize_t display_width_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 config = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.resolution); + + return sprintf(buf, "%u\n", config >> 16); +} + +static ssize_t display_width_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 0xFFFF) + return -EINVAL; + + mutex_lock(voutdev->vdev.lock); + if (vb2_is_busy(voutdev->vdev.queue)) { + mutex_unlock(voutdev->vdev.lock); + return -EBUSY; + } + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.resolution, + 0xFFFF0000, val << 16); + + mutex_unlock(voutdev->vdev.lock); + + return count; +} + +static ssize_t display_height_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 config = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.resolution); + + return sprintf(buf, "%u\n", config & 0xFFFF); +} + +static ssize_t display_height_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 0xFFFF) + return -EINVAL; + + mutex_lock(voutdev->vdev.lock); + if (vb2_is_busy(voutdev->vdev.queue)) { + mutex_unlock(voutdev->vdev.lock); + return -EBUSY; + } + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.resolution, + 0xFFFF, val); + + mutex_unlock(voutdev->vdev.lock); + + return count; +} + +static ssize_t frame_rate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 period = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.frame_period); + + return sprintf(buf, "%u\n", 125000000 / period); +} + +/* + * Frame rate change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t frame_rate_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + mgb4_write_reg(&voutdev->mgbdev->video, + voutdev->config->regs.frame_period, 125000000 / val); + + return count; +} + +static ssize_t hsync_width_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.hsync); + + return sprintf(buf, "%u\n", (sig & 0x00FF0000) >> 16); +} + +/* + * HSYNC width change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t hsync_width_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 0xFF) + return -EINVAL; + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.hsync, + 0x00FF0000, val << 16); + + return count; +} + +static ssize_t vsync_width_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.vsync); + + return sprintf(buf, "%u\n", (sig & 0x00FF0000) >> 16); +} + +/* + * VSYNC vidth change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t vsync_width_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 0xFF) + return -EINVAL; + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.vsync, + 0x00FF0000, val << 16); + + return count; +} + +static ssize_t hback_porch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.hsync); + + return sprintf(buf, "%u\n", (sig & 0x0000FF00) >> 8); +} + +/* + * hback porch change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t hback_porch_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 0xFF) + return -EINVAL; + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.hsync, + 0x0000FF00, val << 8); + + return count; +} + +static ssize_t vback_porch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.vsync); + + return sprintf(buf, "%u\n", (sig & 0x0000FF00) >> 8); +} + +/* + * vback porch change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t vback_porch_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 0xFF) + return -EINVAL; + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.vsync, + 0x0000FF00, val << 8); + + return count; +} + +static ssize_t hfront_porch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.hsync); + + return sprintf(buf, "%u\n", (sig & 0x000000FF)); +} + +/* + * hfront porch change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t hfront_porch_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 0xFF) + return -EINVAL; + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.hsync, + 0x000000FF, val); + + return count; +} + +static ssize_t vfront_porch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.vsync); + + return sprintf(buf, "%u\n", (sig & 0x000000FF)); +} + +/* + * vfront porch change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t vfront_porch_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 0xFF) + return -EINVAL; + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.vsync, + 0x000000FF, val); + + return count; +} + +/* FPDL3 only */ + +static ssize_t hsync_polarity_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 config = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.hsync); + + return sprintf(buf, "%u\n", (config & (1U << 31)) >> 31); +} + +/* + * HSYNC polarity change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t hsync_polarity_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 1) + return -EINVAL; + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.hsync, + (1U << 31), val << 31); + + return count; +} + +static ssize_t vsync_polarity_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 config = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.vsync); + + return sprintf(buf, "%u\n", (config & (1U << 31)) >> 31); +} + +/* + * VSYNC polarity change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t vsync_polarity_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 1) + return -EINVAL; + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.vsync, + (1U << 31), val << 31); + + return count; +} + +static ssize_t de_polarity_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 config = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.vsync); + + return sprintf(buf, "%u\n", (config & (1U << 30)) >> 30); +} + +/* + * DE polarity change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t de_polarity_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 1) + return -EINVAL; + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.vsync, + (1U << 30), val << 30); + + return count; +} + +static ssize_t fpdl3_output_width_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + s32 ret; + + mutex_lock(&voutdev->mgbdev->i2c_lock); + ret = mgb4_i2c_read_byte(&voutdev->ser, 0x5B); + mutex_unlock(&voutdev->mgbdev->i2c_lock); + if (ret < 0) + return -EIO; + + switch ((u8)ret & 0x03) { + case 0: + return sprintf(buf, "0\n"); + case 1: + return sprintf(buf, "1\n"); + case 3: + return sprintf(buf, "2\n"); + default: + return -EINVAL; + } +} + +/* + * FPD-Link width change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t fpdl3_output_width_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u8 i2c_data; + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + switch (val) { + case 0: /* auto */ + i2c_data = 0x00; + break; + case 1: /* single */ + i2c_data = 0x01; + break; + case 2: /* dual */ + i2c_data = 0x03; + break; + default: + return -EINVAL; + } + + mutex_lock(&voutdev->mgbdev->i2c_lock); + ret = mgb4_i2c_mask_byte(&voutdev->ser, 0x5B, 0x03, i2c_data); + mutex_unlock(&voutdev->mgbdev->i2c_lock); + if (ret < 0) + return -EIO; + + return count; +} + +static ssize_t pclk_frequency_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + + return sprintf(buf, "%u\n", voutdev->freq); +} + +static ssize_t pclk_frequency_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + unsigned int dp; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + mutex_lock(voutdev->vdev.lock); + if (vb2_is_busy(voutdev->vdev.queue)) { + mutex_unlock(voutdev->vdev.lock); + return -EBUSY; + } + + dp = (val > 50000) ? 1 : 0; + voutdev->freq = mgb4_cmt_set_vout_freq(voutdev, val >> dp) << dp; + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.config, + 0x10, dp << 4); + mutex_lock(&voutdev->mgbdev->i2c_lock); + ret = mgb4_i2c_mask_byte(&voutdev->ser, 0x4F, 1 << 6, ((~dp) & 1) << 6); + mutex_unlock(&voutdev->mgbdev->i2c_lock); + + mutex_unlock(voutdev->vdev.lock); + + return (ret < 0) ? -EIO : count; +} + +static DEVICE_ATTR_RO(output_id); +static DEVICE_ATTR_RW(video_source); +static DEVICE_ATTR_RW(display_width); +static DEVICE_ATTR_RW(display_height); +static DEVICE_ATTR_RW(frame_rate); +static DEVICE_ATTR_RW(hsync_polarity); +static DEVICE_ATTR_RW(vsync_polarity); +static DEVICE_ATTR_RW(de_polarity); +static DEVICE_ATTR_RW(pclk_frequency); +static DEVICE_ATTR_RW(hsync_width); +static DEVICE_ATTR_RW(vsync_width); +static DEVICE_ATTR_RW(hback_porch); +static DEVICE_ATTR_RW(hfront_porch); +static DEVICE_ATTR_RW(vback_porch); +static DEVICE_ATTR_RW(vfront_porch); + +static DEVICE_ATTR_RW(fpdl3_output_width); + +struct attribute *mgb4_fpdl3_out_attrs[] = { + &dev_attr_output_id.attr, + &dev_attr_video_source.attr, + &dev_attr_display_width.attr, + &dev_attr_display_height.attr, + &dev_attr_frame_rate.attr, + &dev_attr_hsync_polarity.attr, + &dev_attr_vsync_polarity.attr, + &dev_attr_de_polarity.attr, + &dev_attr_pclk_frequency.attr, + &dev_attr_hsync_width.attr, + &dev_attr_vsync_width.attr, + &dev_attr_hback_porch.attr, + &dev_attr_hfront_porch.attr, + &dev_attr_vback_porch.attr, + &dev_attr_vfront_porch.attr, + &dev_attr_fpdl3_output_width.attr, + NULL +}; + +struct attribute *mgb4_gmsl_out_attrs[] = { + &dev_attr_output_id.attr, + &dev_attr_video_source.attr, + &dev_attr_display_width.attr, + &dev_attr_display_height.attr, + &dev_attr_frame_rate.attr, + NULL +}; diff --git a/drivers/media/pci/mgb4/mgb4_sysfs_pci.c b/drivers/media/pci/mgb4/mgb4_sysfs_pci.c new file mode 100644 index 0000000000000..d26935ff956b6 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_sysfs_pci.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 Digiteq Automotive + * author: Martin Tuma + * + * This module handles all the sysfs info/configuration that is related to the + * PCI card device. + */ + +#include +#include "mgb4_core.h" +#include "mgb4_sysfs.h" + +static ssize_t module_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mgb4_dev *mgbdev = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", mgbdev->module_version & 0x0F); +} + +static ssize_t module_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mgb4_dev *mgbdev = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", mgbdev->module_version >> 4); +} + +static ssize_t fw_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mgb4_dev *mgbdev = dev_get_drvdata(dev); + u32 config = mgb4_read_reg(&mgbdev->video, 0xC4); + + return sprintf(buf, "%u\n", config & 0xFFFF); +} + +static ssize_t fw_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mgb4_dev *mgbdev = dev_get_drvdata(dev); + u32 config = mgb4_read_reg(&mgbdev->video, 0xC4); + + return sprintf(buf, "%u\n", config >> 24); +} + +static ssize_t serial_number_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mgb4_dev *mgbdev = dev_get_drvdata(dev); + u32 sn = mgbdev->serial_number; + + return sprintf(buf, "%03d-%03d-%03d-%03d\n", sn >> 24, (sn >> 16) & 0xFF, + (sn >> 8) & 0xFF, sn & 0xFF); +} + +static DEVICE_ATTR_RO(module_version); +static DEVICE_ATTR_RO(module_type); +static DEVICE_ATTR_RO(fw_version); +static DEVICE_ATTR_RO(fw_type); +static DEVICE_ATTR_RO(serial_number); + +struct attribute *mgb4_pci_attrs[] = { + &dev_attr_module_type.attr, + &dev_attr_module_version.attr, + &dev_attr_fw_type.attr, + &dev_attr_fw_version.attr, + &dev_attr_serial_number.attr, + NULL +}; diff --git a/drivers/media/pci/mgb4/mgb4_trigger.c b/drivers/media/pci/mgb4/mgb4_trigger.c new file mode 100644 index 0000000000000..923650d53d4c8 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_trigger.c @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma + * + * This module handles the IIO trigger device. The card has two signal inputs + * for event triggers that can be used to record events related to the video + * stream. A standard linux IIO device with triggered buffer capability is + * created and configured that can be used to fetch the events with the same + * clock source as the video frames. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "mgb4_core.h" +#include "mgb4_trigger.h" + +struct trigger_data { + struct mgb4_dev *mgbdev; + struct iio_trigger *trig; +}; + +static int trigger_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct trigger_data *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + *val = mgb4_read_reg(&st->mgbdev->video, 0xA0); + + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static int trigger_set_state(struct iio_trigger *trig, bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct trigger_data *st = iio_priv(indio_dev); + int irq = xdma_get_user_irq(st->mgbdev->xdev, 11); + + if (state) + xdma_enable_user_irq(st->mgbdev->xdev, irq); + else + xdma_disable_user_irq(st->mgbdev->xdev, irq); + + return 0; +} + +static const struct iio_trigger_ops trigger_ops = { + .set_trigger_state = &trigger_set_state, +}; + +static const struct iio_info trigger_info = { + .read_raw = trigger_read_raw, +}; + +#define TRIGGER_CHANNEL(_si) { \ + .type = IIO_ACTIVITY, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .scan_index = _si, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 32, \ + .storagebits = 32, \ + .shift = 0, \ + .endianness = IIO_CPU \ + }, \ +} + +static const struct iio_chan_spec trigger_channels[] = { + TRIGGER_CHANNEL(0), + IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static irqreturn_t trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct trigger_data *st = iio_priv(indio_dev); + struct { + u32 data; + s64 ts __aligned(8); + } scan; + + scan.data = mgb4_read_reg(&st->mgbdev->video, 0xA0); + mgb4_write_reg(&st->mgbdev->video, 0xA0, scan.data); + + iio_push_to_buffers_with_timestamp(indio_dev, &scan, pf->timestamp); + iio_trigger_notify_done(indio_dev->trig); + + mgb4_write_reg(&st->mgbdev->video, 0xB4, 1U << 11); + + return IRQ_HANDLED; +} + +static int probe_trigger(struct iio_dev *indio_dev, int irq) +{ + int ret; + struct trigger_data *st = iio_priv(indio_dev); + + st->trig = iio_trigger_alloc(&st->mgbdev->pdev->dev, "%s-dev%d", + indio_dev->name, iio_device_id(indio_dev)); + if (!st->trig) + return -ENOMEM; + + ret = request_irq(irq, &iio_trigger_generic_data_rdy_poll, 0, + "mgb4-trigger", st->trig); + if (ret) + goto error_free_trig; + + st->trig->ops = &trigger_ops; + iio_trigger_set_drvdata(st->trig, indio_dev); + ret = iio_trigger_register(st->trig); + if (ret) + goto error_free_irq; + + indio_dev->trig = iio_trigger_get(st->trig); + + return 0; + +error_free_irq: + free_irq(irq, st->trig); +error_free_trig: + iio_trigger_free(st->trig); + + return ret; +} + +static void remove_trigger(struct iio_dev *indio_dev, int irq) +{ + struct trigger_data *st = iio_priv(indio_dev); + + iio_trigger_unregister(st->trig); + free_irq(irq, st->trig); + iio_trigger_free(st->trig); +} + +struct iio_dev *mgb4_trigger_create(struct mgb4_dev *mgbdev) +{ + struct iio_dev *indio_dev; + struct trigger_data *data; + struct pci_dev *pdev = mgbdev->pdev; + struct device *dev = &pdev->dev; + int rv, irq; + + indio_dev = iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return NULL; + + indio_dev->info = &trigger_info; + indio_dev->name = "mgb4"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = trigger_channels; + indio_dev->num_channels = ARRAY_SIZE(trigger_channels); + + data = iio_priv(indio_dev); + data->mgbdev = mgbdev; + + irq = xdma_get_user_irq(mgbdev->xdev, 11); + rv = probe_trigger(indio_dev, irq); + if (rv < 0) { + dev_err(dev, "iio triggered setup failed\n"); + goto error_alloc; + } + rv = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + trigger_handler, NULL); + if (rv < 0) { + dev_err(dev, "iio triggered buffer setup failed\n"); + goto error_trigger; + } + rv = iio_device_register(indio_dev); + if (rv < 0) { + dev_err(dev, "iio device register failed\n"); + goto error_buffer; + } + + return indio_dev; + +error_buffer: + iio_triggered_buffer_cleanup(indio_dev); +error_trigger: + remove_trigger(indio_dev, irq); +error_alloc: + iio_device_free(indio_dev); + + return NULL; +} + +void mgb4_trigger_free(struct iio_dev *indio_dev) +{ + struct trigger_data *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + remove_trigger(indio_dev, xdma_get_user_irq(st->mgbdev->xdev, 11)); + iio_device_free(indio_dev); +} diff --git a/drivers/media/pci/mgb4/mgb4_trigger.h b/drivers/media/pci/mgb4/mgb4_trigger.h new file mode 100644 index 0000000000000..6c25bc4576f6e --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_trigger.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021-2022 Digiteq Automotive + * author: Martin Tuma + */ + +struct iio_dev *mgb4_trigger_create(struct mgb4_dev *mgbdev); +void mgb4_trigger_free(struct iio_dev *indio_dev); diff --git a/drivers/media/pci/mgb4/mgb4_vin.c b/drivers/media/pci/mgb4/mgb4_vin.c new file mode 100644 index 0000000000000..d72b07b87cd10 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_vin.c @@ -0,0 +1,939 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma + * + * This is the v4l2 input device module. It initializes the signal deserializers + * and creates the v4l2 video devices. The input signal can change at any time + * which is handled by the "timings" callbacks and an IRQ based watcher, that + * emits the V4L2_EVENT_SOURCE_CHANGE event in case of a signal source change. + * + * When the device is in loopback mode (a direct, in HW, in->out frame passing + * mode) the card's frame queue must be running regardless of whether a v4l2 + * stream is running and the output parameters like frame buffers padding must + * be in sync with the input parameters. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mgb4_core.h" +#include "mgb4_dma.h" +#include "mgb4_sysfs.h" +#include "mgb4_io.h" +#include "mgb4_vout.h" +#include "mgb4_vin.h" + +ATTRIBUTE_GROUPS(mgb4_fpdl3_in); +ATTRIBUTE_GROUPS(mgb4_gmsl_in); + +static const struct mgb4_vin_config vin_cfg[] = { + {0, 0, 0, 6, {0x10, 0x00, 0x04, 0x08, 0x1C, 0x14, 0x18, 0x20, 0x24, 0x28}}, + {1, 1, 1, 7, {0x40, 0x30, 0x34, 0x38, 0x4C, 0x44, 0x48, 0x50, 0x54, 0x58}} +}; + +static const struct i2c_board_info fpdl3_deser_info[] = { + {I2C_BOARD_INFO("deserializer1", 0x38)}, + {I2C_BOARD_INFO("deserializer2", 0x36)}, +}; + +static const struct i2c_board_info gmsl_deser_info[] = { + {I2C_BOARD_INFO("deserializer1", 0x4C)}, + {I2C_BOARD_INFO("deserializer2", 0x2A)}, +}; + +static const struct mgb4_i2c_kv fpdl3_i2c[] = { + {0x06, 0xFF, 0x04}, {0x07, 0xFF, 0x01}, {0x45, 0xFF, 0xE8}, + {0x49, 0xFF, 0x00}, {0x34, 0xFF, 0x00}, {0x23, 0xFF, 0x00} +}; + +static const struct mgb4_i2c_kv gmsl_i2c[] = { + {0x01, 0x03, 0x03}, {0x300, 0x0C, 0x0C}, {0x03, 0xC0, 0xC0}, + {0x1CE, 0x0E, 0x0E}, {0x11, 0x05, 0x00}, {0x05, 0xC0, 0x40}, + {0x307, 0x0F, 0x00}, {0xA0, 0x03, 0x00}, {0x3E0, 0x07, 0x07}, + {0x308, 0x01, 0x01}, {0x10, 0x20, 0x20}, {0x300, 0x40, 0x40} +}; + +static const struct v4l2_dv_timings_cap video_timings_cap = { + .type = V4L2_DV_BT_656_1120, + .bt = { + .min_width = 320, + .max_width = 4096, + .min_height = 240, + .max_height = 2160, + .min_pixelclock = 1843200, /* 320 x 240 x 24Hz */ + .max_pixelclock = 530841600, /* 4096 x 2160 x 60Hz */ + .standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | + V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF, + .capabilities = V4L2_DV_BT_CAP_PROGRESSIVE | + V4L2_DV_BT_CAP_CUSTOM, + }, +}; + +/* + * Returns the video output connected with the given video input if the input + * is in loopback mode. + */ +static struct mgb4_vout_dev *loopback_dev(struct mgb4_vin_dev *vindev, int i) +{ + struct mgb4_vout_dev *voutdev; + u32 config; + + voutdev = vindev->mgbdev->vout[i]; + if (!voutdev) + return NULL; + + config = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.config); + if ((config & 0xc) >> 2 == vindev->config->id) + return voutdev; + + return NULL; +} + +/* + * Check, whether the loopback mode - a HW INPUT->OUTPUT transmission - is + * enabled on the given input. + */ +static int loopback_active(struct mgb4_vin_dev *vindev) +{ + int i; + + for (i = 0; i < MGB4_VOUT_DEVICES; i++) + if (loopback_dev(vindev, i)) + return 1; + + return 0; +} + +/* + * Set the output frame buffer padding of all outputs connected with the given + * input when the video input is set to loopback mode. The paddings must be + * the same for the loopback to work properly. + */ +static void set_loopback_padding(struct mgb4_vin_dev *vindev, u32 padding) +{ + struct mgb4_regs *video = &vindev->mgbdev->video; + struct mgb4_vout_dev *voutdev; + int i; + + for (i = 0; i < MGB4_VOUT_DEVICES; i++) { + voutdev = loopback_dev(vindev, i); + if (voutdev) + mgb4_write_reg(video, voutdev->config->regs.padding, + padding); + } +} + +static int get_timings(struct mgb4_vin_dev *vindev, + struct v4l2_dv_timings *timings) +{ + struct mgb4_regs *video = &vindev->mgbdev->video; + const struct mgb4_vin_regs *regs = &vindev->config->regs; + + u32 status = mgb4_read_reg(video, regs->status); + u32 pclk = mgb4_read_reg(video, regs->pclk); + u32 signal = mgb4_read_reg(video, regs->signal); + u32 signal2 = mgb4_read_reg(video, regs->signal2); + u32 resolution = mgb4_read_reg(video, regs->resolution); + + if (!(status & (1U << 2))) + return -ENOLCK; + if (!(status & (3 << 9))) + return -ENOLINK; + + memset(timings, 0, sizeof(*timings)); + timings->type = V4L2_DV_BT_656_1120; + timings->bt.width = resolution >> 16; + timings->bt.height = resolution & 0xFFFF; + if (status & (1U << 12)) + timings->bt.polarities |= V4L2_DV_HSYNC_POS_POL; + if (status & (1U << 13)) + timings->bt.polarities |= V4L2_DV_VSYNC_POS_POL; + timings->bt.pixelclock = pclk * 1000; + timings->bt.hsync = (signal & 0x00FF0000) >> 16; + timings->bt.vsync = (signal2 & 0x00FF0000) >> 16; + timings->bt.hbackporch = (signal & 0x0000FF00) >> 8; + timings->bt.hfrontporch = signal & 0x000000FF; + timings->bt.vbackporch = (signal2 & 0x0000FF00) >> 8; + timings->bt.vfrontporch = signal2 & 0x000000FF; + + return 0; +} + +static void return_all_buffers(struct mgb4_vin_dev *vindev, + enum vb2_buffer_state state) +{ + struct mgb4_frame_buffer *buf, *node; + unsigned long flags; + + spin_lock_irqsave(&vindev->qlock, flags); + list_for_each_entry_safe(buf, node, &vindev->buf_list, list) { + vb2_buffer_done(&buf->vb.vb2_buf, state); + list_del(&buf->list); + } + spin_unlock_irqrestore(&vindev->qlock, flags); +} + +static int queue_setup(struct vb2_queue *q, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct mgb4_vin_dev *vindev = vb2_get_drv_priv(q); + unsigned int size = (vindev->timings.bt.width + vindev->padding) + * vindev->timings.bt.height * 4; + + /* + * If I/O reconfiguration is in process, do not allow to start + * the queue. See video_source_store() in mgb4_sysfs_out.c for + * details. + */ + if (test_bit(0, &vindev->mgbdev->io_reconfig)) + return -EBUSY; + + if (!size) + return -EINVAL; + if (*nplanes) + return sizes[0] < size ? -EINVAL : 0; + *nplanes = 1; + sizes[0] = size; + + return 0; +} + +static int buffer_init(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct mgb4_frame_buffer *buf = to_frame_buffer(vbuf); + + INIT_LIST_HEAD(&buf->list); + + return 0; +} + +static int buffer_prepare(struct vb2_buffer *vb) +{ + struct mgb4_vin_dev *vindev = vb2_get_drv_priv(vb->vb2_queue); + struct device *dev = &vindev->mgbdev->pdev->dev; + unsigned int size = (vindev->timings.bt.width + vindev->padding) + * vindev->timings.bt.height * 4; + + if (vb2_plane_size(vb, 0) < size) { + dev_err(dev, "buffer too small (%lu < %u)\n", + vb2_plane_size(vb, 0), size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, size); + + return 0; +} + +static void buffer_queue(struct vb2_buffer *vb) +{ + struct mgb4_vin_dev *vindev = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct mgb4_frame_buffer *buf = to_frame_buffer(vbuf); + unsigned long flags; + + spin_lock_irqsave(&vindev->qlock, flags); + list_add_tail(&buf->list, &vindev->buf_list); + spin_unlock_irqrestore(&vindev->qlock, flags); +} + +static void stop_streaming(struct vb2_queue *vq) +{ + struct mgb4_vin_dev *vindev = vb2_get_drv_priv(vq); + const struct mgb4_vin_config *config = vindev->config; + int irq = xdma_get_user_irq(vindev->mgbdev->xdev, config->vin_irq); + + xdma_disable_user_irq(vindev->mgbdev->xdev, irq); + + /* + * In loopback mode, the HW frame queue must be left running for + * the IN->OUT transmission to work! + */ + if (!loopback_active(vindev)) + mgb4_mask_reg(&vindev->mgbdev->video, config->regs.config, 0x2, + 0x0); + + cancel_work_sync(&vindev->dma_work); + return_all_buffers(vindev, VB2_BUF_STATE_ERROR); +} + +static int start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct mgb4_vin_dev *vindev = vb2_get_drv_priv(vq); + const struct mgb4_vin_config *config = vindev->config; + int irq = xdma_get_user_irq(vindev->mgbdev->xdev, config->vin_irq); + + vindev->sequence = 0; + + /* + * In loopback mode, the HW frame queue is already running. + */ + if (!loopback_active(vindev)) + mgb4_mask_reg(&vindev->mgbdev->video, config->regs.config, 0x2, + 0x2); + + xdma_enable_user_irq(vindev->mgbdev->xdev, irq); + + return 0; +} + +static const struct vb2_ops queue_ops = { + .queue_setup = queue_setup, + .buf_init = buffer_init, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .start_streaming = start_streaming, + .stop_streaming = stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish +}; + +static int fh_open(struct file *file) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + int rv; + + mutex_lock(&vindev->lock); + + rv = v4l2_fh_open(file); + if (rv) + goto out; + + if (!v4l2_fh_is_singular_file(file)) + goto out; + + get_timings(vindev, &vindev->timings); + set_loopback_padding(vindev, vindev->padding); + +out: + mutex_unlock(&vindev->lock); + return rv; +} + +static int fh_release(struct file *file) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + int rv; + + mutex_lock(&vindev->lock); + + if (v4l2_fh_is_singular_file(file)) + set_loopback_padding(vindev, 0); + + rv = _vb2_fop_release(file, NULL); + + mutex_unlock(&vindev->lock); + + return rv; +} + +static const struct v4l2_file_operations video_fops = { + .owner = THIS_MODULE, + .open = fh_open, + .release = fh_release, + .unlocked_ioctl = video_ioctl2, + .read = vb2_fop_read, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, +}; + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); + strscpy(cap->card, "MGB4 PCIe Card", sizeof(cap->card)); + + return 0; +} + +static int vidioc_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index != 0) + return -EINVAL; + + f->pixelformat = V4L2_PIX_FMT_ABGR32; + + return 0; +} + +static int vidioc_enum_frameintervals(struct file *file, void *priv, + struct v4l2_frmivalenum *ival) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + + if (ival->index != 0) + return -EINVAL; + if (ival->pixel_format != V4L2_PIX_FMT_ABGR32) + return -EINVAL; + if (ival->width != vindev->timings.bt.width || + ival->height != vindev->timings.bt.height) + return -EINVAL; + + ival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; + ival->stepwise.min.denominator = 60; + ival->stepwise.min.numerator = 1; + ival->stepwise.max.denominator = 1; + ival->stepwise.max.numerator = 1; + ival->stepwise.step = ival->stepwise.max; + + return 0; +} + +static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + + f->fmt.pix.pixelformat = V4L2_PIX_FMT_ABGR32; + f->fmt.pix.width = vindev->timings.bt.width; + f->fmt.pix.height = vindev->timings.bt.height; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW; + f->fmt.pix.bytesperline = (f->fmt.pix.width + vindev->padding) * 4; + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; + + return 0; +} + +static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + + f->fmt.pix.pixelformat = V4L2_PIX_FMT_ABGR32; + f->fmt.pix.width = vindev->timings.bt.width; + f->fmt.pix.height = vindev->timings.bt.height; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW; + f->fmt.pix.bytesperline = max(f->fmt.pix.width * 4, + ALIGN_DOWN(f->fmt.pix.bytesperline, 4)); + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; + + return 0; +} + +static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + struct mgb4_regs *video = &vindev->mgbdev->video; + + if (vb2_is_busy(&vindev->queue)) + return -EBUSY; + + vidioc_try_fmt(file, priv, f); + + vindev->padding = (f->fmt.pix.bytesperline - (f->fmt.pix.width * 4)) / 4; + mgb4_write_reg(video, vindev->config->regs.padding, vindev->padding); + set_loopback_padding(vindev, vindev->padding); + + return 0; +} + +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + struct mgb4_regs *video = &vindev->mgbdev->video; + u32 status; + + if (i->index != 0) + return -EINVAL; + + strscpy(i->name, "MGB4", sizeof(i->name)); + i->type = V4L2_INPUT_TYPE_CAMERA; + i->capabilities = V4L2_IN_CAP_DV_TIMINGS; + i->status = 0; + + status = mgb4_read_reg(video, vindev->config->regs.status); + if (!(status & (1U << 2))) + i->status |= V4L2_IN_ST_NO_SYNC; + if (!(status & (3 << 9))) + i->status |= V4L2_IN_ST_NO_SIGNAL; + + return 0; +} + +static int vidioc_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + + if (fsize->index != 0 || fsize->pixel_format != V4L2_PIX_FMT_ABGR32) + return -EINVAL; + + fsize->discrete.width = vindev->timings.bt.width; + fsize->discrete.height = vindev->timings.bt.height; + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + + return 0; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + return (i == 0) ? 0 : -EINVAL; +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_parm(struct file *file, void *priv, + struct v4l2_streamparm *parm) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + struct mgb4_regs *video = &vindev->mgbdev->video; + const struct mgb4_vin_regs *regs = &vindev->config->regs; + struct v4l2_fract timeperframe = { + .numerator = mgb4_read_reg(video, regs->frame_period), + .denominator = 125000000, + }; + + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + parm->parm.capture.readbuffers = 2; + parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + parm->parm.capture.timeperframe = timeperframe; + + return 0; +} + +static int vidioc_s_dv_timings(struct file *file, void *fh, + struct v4l2_dv_timings *timings) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + + if (timings->bt.width < video_timings_cap.bt.min_width || + timings->bt.width > video_timings_cap.bt.max_width || + timings->bt.height < video_timings_cap.bt.min_height || + timings->bt.height > video_timings_cap.bt.max_height) + return -EINVAL; + if (timings->bt.width == vindev->timings.bt.width && + timings->bt.height == vindev->timings.bt.height) + return 0; + if (vb2_is_busy(&vindev->queue)) + return -EBUSY; + + vindev->timings = *timings; + + return 0; +} + +static int vidioc_g_dv_timings(struct file *file, void *fh, + struct v4l2_dv_timings *timings) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + *timings = vindev->timings; + + return 0; +} + +static int vidioc_query_dv_timings(struct file *file, void *fh, + struct v4l2_dv_timings *timings) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + + return get_timings(vindev, timings); +} + +static int vidioc_enum_dv_timings(struct file *file, void *fh, + struct v4l2_enum_dv_timings *timings) +{ + return v4l2_enum_dv_timings_cap(timings, &video_timings_cap, NULL, NULL); +} + +static int vidioc_dv_timings_cap(struct file *file, void *fh, + struct v4l2_dv_timings_cap *cap) +{ + *cap = video_timings_cap; + + return 0; +} + +static int vidioc_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subscribe(fh, sub); + } + + return v4l2_ctrl_subscribe_event(fh, sub); +} + +static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt, + .vidioc_enum_framesizes = vidioc_enum_framesizes, + .vidioc_enum_frameintervals = vidioc_enum_frameintervals, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_g_parm = vidioc_parm, + .vidioc_s_parm = vidioc_parm, + .vidioc_dv_timings_cap = vidioc_dv_timings_cap, + .vidioc_enum_dv_timings = vidioc_enum_dv_timings, + .vidioc_g_dv_timings = vidioc_g_dv_timings, + .vidioc_s_dv_timings = vidioc_s_dv_timings, + .vidioc_query_dv_timings = vidioc_query_dv_timings, + .vidioc_subscribe_event = vidioc_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static void dma_transfer(struct work_struct *work) +{ + struct mgb4_vin_dev *vindev = container_of(work, struct mgb4_vin_dev, + dma_work); + struct mgb4_regs *video = &vindev->mgbdev->video; + struct device *dev = &vindev->mgbdev->pdev->dev; + struct mgb4_frame_buffer *buf = NULL; + unsigned long flags; + u32 addr; + int rv; + + spin_lock_irqsave(&vindev->qlock, flags); + if (!list_empty(&vindev->buf_list)) { + buf = list_first_entry(&vindev->buf_list, + struct mgb4_frame_buffer, list); + list_del_init(vindev->buf_list.next); + } + spin_unlock_irqrestore(&vindev->qlock, flags); + + if (!buf) + return; + + addr = mgb4_read_reg(video, vindev->config->regs.address); + if (addr >= MGB4_ERR_QUEUE_FULL) { + dev_dbg(dev, "frame queue error (%d)\n", (int)addr); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + return; + } + + rv = mgb4_dma_transfer(vindev->mgbdev, vindev->config->dma_channel, + false, addr, + vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0)); + if (rv < 0) { + dev_warn(dev, "DMA transfer error\n"); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } else { + buf->vb.vb2_buf.timestamp = ktime_get_ns(); + buf->vb.sequence = vindev->sequence++; + buf->vb.field = V4L2_FIELD_NONE; + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + } +} + +static void signal_change(struct work_struct *work) +{ + struct mgb4_vin_dev *vindev = container_of(work, struct mgb4_vin_dev, + err_work); + struct mgb4_regs *video = &vindev->mgbdev->video; + struct v4l2_bt_timings *timings = &vindev->timings.bt; + struct device *dev = &vindev->mgbdev->pdev->dev; + + u32 resolution = mgb4_read_reg(video, vindev->config->regs.resolution); + u32 width = resolution >> 16; + u32 height = resolution & 0xFFFF; + + if (timings->width != width || timings->height != height) { + static const struct v4l2_event ev = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + + v4l2_event_queue(&vindev->vdev, &ev); + + if (vb2_is_streaming(&vindev->queue)) + vb2_queue_error(&vindev->queue); + } + + dev_dbg(dev, "stream changed to %ux%u\n", width, height); +} + +static irqreturn_t vin_handler(int irq, void *ctx) +{ + struct mgb4_vin_dev *vindev = (struct mgb4_vin_dev *)ctx; + struct mgb4_regs *video = &vindev->mgbdev->video; + + schedule_work(&vindev->dma_work); + + mgb4_write_reg(video, 0xB4, 1U << vindev->config->vin_irq); + + return IRQ_HANDLED; +} + +static irqreturn_t err_handler(int irq, void *ctx) +{ + struct mgb4_vin_dev *vindev = (struct mgb4_vin_dev *)ctx; + struct mgb4_regs *video = &vindev->mgbdev->video; + + schedule_work(&vindev->err_work); + + mgb4_write_reg(video, 0xB4, 1U << vindev->config->err_irq); + + return IRQ_HANDLED; +} + +static int deser_init(struct mgb4_vin_dev *vindev, int id) +{ + int rv, addr_size; + size_t values_count; + const struct mgb4_i2c_kv *values; + const struct i2c_board_info *info; + struct device *dev = &vindev->mgbdev->pdev->dev; + + if (MGB4_IS_GMSL(vindev->mgbdev)) { + info = &gmsl_deser_info[id]; + addr_size = 16; + values = gmsl_i2c; + values_count = ARRAY_SIZE(gmsl_i2c); + } else { + info = &fpdl3_deser_info[id]; + addr_size = 8; + values = fpdl3_i2c; + values_count = ARRAY_SIZE(fpdl3_i2c); + } + + rv = mgb4_i2c_init(&vindev->deser, vindev->mgbdev->i2c_adap, info, + addr_size); + if (rv < 0) { + dev_err(dev, "failed to create deserializer\n"); + return rv; + } + rv = mgb4_i2c_configure(&vindev->deser, values, values_count); + if (rv < 0) { + dev_err(dev, "failed to configure deserializer\n"); + goto err_i2c_dev; + } + + return 0; + +err_i2c_dev: + mgb4_i2c_free(&vindev->deser); + + return rv; +} + +static void fpga_init(struct mgb4_vin_dev *vindev) +{ + struct mgb4_regs *video = &vindev->mgbdev->video; + const struct mgb4_vin_regs *regs = &vindev->config->regs; + + mgb4_write_reg(video, regs->config, 0x00000001); + mgb4_write_reg(video, regs->sync, 0x03E80002); + mgb4_write_reg(video, regs->padding, 0x00000000); + mgb4_write_reg(video, regs->config, 1U << 9); +} + +#ifdef CONFIG_DEBUG_FS +static void debugfs_init(struct mgb4_vin_dev *vindev) +{ + struct mgb4_regs *video = &vindev->mgbdev->video; + + vindev->debugfs = debugfs_create_dir(vindev->vdev.name, + vindev->mgbdev->debugfs); + if (!vindev->debugfs) + return; + + vindev->regs[0].name = "CONFIG"; + vindev->regs[0].offset = vindev->config->regs.config; + vindev->regs[1].name = "STATUS"; + vindev->regs[1].offset = vindev->config->regs.status; + vindev->regs[2].name = "RESOLUTION"; + vindev->regs[2].offset = vindev->config->regs.resolution; + vindev->regs[3].name = "FRAME_PERIOD"; + vindev->regs[3].offset = vindev->config->regs.frame_period; + vindev->regs[4].name = "HS_VS_GENER_SETTINGS"; + vindev->regs[4].offset = vindev->config->regs.sync; + vindev->regs[5].name = "PCLK_FREQUENCY"; + vindev->regs[5].offset = vindev->config->regs.pclk; + vindev->regs[6].name = "VIDEO_PARAMS_1"; + vindev->regs[6].offset = vindev->config->regs.signal; + vindev->regs[7].name = "VIDEO_PARAMS_2"; + vindev->regs[7].offset = vindev->config->regs.signal2; + vindev->regs[8].name = "PADDING_PIXELS"; + vindev->regs[8].offset = vindev->config->regs.padding; + + vindev->regset.base = video->membase; + vindev->regset.regs = vindev->regs; + vindev->regset.nregs = ARRAY_SIZE(vindev->regs); + + debugfs_create_regset32("registers", 0444, vindev->debugfs, + &vindev->regset); +} +#endif + +struct mgb4_vin_dev *mgb4_vin_create(struct mgb4_dev *mgbdev, int id) +{ + int rv; + const struct attribute_group **groups; + struct mgb4_vin_dev *vindev; + struct pci_dev *pdev = mgbdev->pdev; + struct device *dev = &pdev->dev; + int vin_irq, err_irq; + + vindev = kzalloc(sizeof(*vindev), GFP_KERNEL); + if (!vindev) + return NULL; + + vindev->mgbdev = mgbdev; + vindev->config = &vin_cfg[id]; + + /* Frame queue*/ + INIT_LIST_HEAD(&vindev->buf_list); + spin_lock_init(&vindev->qlock); + + /* Work queues */ + INIT_WORK(&vindev->dma_work, dma_transfer); + INIT_WORK(&vindev->err_work, signal_change); + + /* IRQ callback */ + vin_irq = xdma_get_user_irq(mgbdev->xdev, vindev->config->vin_irq); + rv = request_irq(vin_irq, vin_handler, 0, "mgb4-vin", vindev); + if (rv) { + dev_err(dev, "failed to register vin irq handler\n"); + goto err_alloc; + } + /* Error IRQ callback */ + err_irq = xdma_get_user_irq(mgbdev->xdev, vindev->config->err_irq); + rv = request_irq(err_irq, err_handler, 0, "mgb4-err", vindev); + if (rv) { + dev_err(dev, "failed to register err irq handler\n"); + goto err_vin_irq; + } + + /* Set the FPGA registers default values */ + fpga_init(vindev); + + /* Set the deserializer default values */ + rv = deser_init(vindev, id); + if (rv) + goto err_err_irq; + + /* V4L2 stuff init */ + rv = v4l2_device_register(dev, &vindev->v4l2dev); + if (rv) { + dev_err(dev, "failed to register v4l2 device\n"); + goto err_err_irq; + } + + mutex_init(&vindev->lock); + + vindev->queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vindev->queue.io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; + vindev->queue.buf_struct_size = sizeof(struct mgb4_frame_buffer); + vindev->queue.ops = &queue_ops; + vindev->queue.mem_ops = &vb2_dma_sg_memops; + vindev->queue.gfp_flags = GFP_DMA32; + vindev->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vindev->queue.min_buffers_needed = 2; + vindev->queue.drv_priv = vindev; + vindev->queue.lock = &vindev->lock; + vindev->queue.dev = dev; + rv = vb2_queue_init(&vindev->queue); + if (rv) { + dev_err(dev, "failed to initialize vb2 queue\n"); + goto err_v4l2_dev; + } + + snprintf(vindev->vdev.name, sizeof(vindev->vdev.name), "mgb4-in%d", + id + 1); + vindev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE + | V4L2_CAP_STREAMING; + vindev->vdev.fops = &video_fops; + vindev->vdev.ioctl_ops = &video_ioctl_ops; + vindev->vdev.release = video_device_release_empty; + vindev->vdev.v4l2_dev = &vindev->v4l2dev; + vindev->vdev.lock = &vindev->lock; + vindev->vdev.queue = &vindev->queue; + video_set_drvdata(&vindev->vdev, vindev); + + /* Enable the video signal change watcher */ + xdma_enable_user_irq(vindev->mgbdev->xdev, err_irq); + + /* Register the video device */ + rv = video_register_device(&vindev->vdev, VFL_TYPE_VIDEO, -1); + if (rv) { + dev_err(dev, "failed to register video device\n"); + goto err_v4l2_dev; + } + + /* Module sysfs attributes */ + groups = MGB4_IS_GMSL(mgbdev) + ? mgb4_gmsl_in_groups : mgb4_fpdl3_in_groups; + rv = device_add_groups(&vindev->vdev.dev, groups); + if (rv) { + dev_err(dev, "failed to create sysfs attributes\n"); + goto err_video_dev; + } + +#ifdef CONFIG_DEBUG_FS + debugfs_init(vindev); +#endif + + return vindev; + +err_video_dev: + video_unregister_device(&vindev->vdev); +err_v4l2_dev: + v4l2_device_unregister(&vindev->v4l2dev); +err_err_irq: + free_irq(err_irq, vindev); +err_vin_irq: + free_irq(vin_irq, vindev); +err_alloc: + kfree(vindev); + + return NULL; +} + +void mgb4_vin_free(struct mgb4_vin_dev *vindev) +{ + const struct attribute_group **groups; + int vin_irq = xdma_get_user_irq(vindev->mgbdev->xdev, + vindev->config->vin_irq); + int err_irq = xdma_get_user_irq(vindev->mgbdev->xdev, + vindev->config->err_irq); + + xdma_disable_user_irq(vindev->mgbdev->xdev, err_irq); + + free_irq(vin_irq, vindev); + free_irq(err_irq, vindev); + +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(vindev->debugfs); +#endif + + groups = MGB4_IS_GMSL(vindev->mgbdev) + ? mgb4_gmsl_in_groups : mgb4_fpdl3_in_groups; + device_remove_groups(&vindev->vdev.dev, groups); + + mgb4_i2c_free(&vindev->deser); + video_unregister_device(&vindev->vdev); + v4l2_device_unregister(&vindev->v4l2dev); + + kfree(vindev); +} diff --git a/drivers/media/pci/mgb4/mgb4_vin.h b/drivers/media/pci/mgb4/mgb4_vin.h new file mode 100644 index 0000000000000..0249b400ad4d7 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_vin.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma + */ + +#ifndef __MGB4_VIN_H__ +#define __MGB4_VIN_H__ + +#include +#include +#include +#include +#include +#include "mgb4_i2c.h" + +struct mgb4_vin_regs { + u32 address; + u32 config; + u32 status; + u32 resolution; + u32 frame_period; + u32 sync; + u32 pclk; + u32 signal; + u32 signal2; + u32 padding; +}; + +struct mgb4_vin_config { + int id; + int dma_channel; + int vin_irq; + int err_irq; + struct mgb4_vin_regs regs; +}; + +struct mgb4_vin_dev { + struct mgb4_dev *mgbdev; + struct v4l2_device v4l2dev; + struct video_device vdev; + struct vb2_queue queue; + struct mutex lock; /* vdev lock */ + + spinlock_t qlock; /* video buffer queue lock */ + struct list_head buf_list; + struct work_struct dma_work, err_work; + + unsigned int sequence; + + struct v4l2_dv_timings timings; + u32 freq_range; + u32 padding; + + struct mgb4_i2c_client deser; + + const struct mgb4_vin_config *config; + +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs; + struct debugfs_regset32 regset; + struct debugfs_reg32 regs[9]; +#endif +}; + +struct mgb4_vin_dev *mgb4_vin_create(struct mgb4_dev *mgbdev, int id); +void mgb4_vin_free(struct mgb4_vin_dev *vindev); + +#endif diff --git a/drivers/media/pci/mgb4/mgb4_vout.c b/drivers/media/pci/mgb4/mgb4_vout.c new file mode 100644 index 0000000000000..857fc7bbd21a8 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_vout.c @@ -0,0 +1,602 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma + * + * This is the v4l2 output device module. It initializes the signal serializers + * and creates the v4l2 video devices. + * + * When the device is in loopback mode (a direct, in HW, in->out frame passing + * mode) we disable the v4l2 output by returning EBUSY in the open() syscall. + */ + +#include +#include +#include +#include +#include +#include +#include "mgb4_core.h" +#include "mgb4_dma.h" +#include "mgb4_sysfs.h" +#include "mgb4_io.h" +#include "mgb4_cmt.h" +#include "mgb4_vout.h" + +ATTRIBUTE_GROUPS(mgb4_fpdl3_out); +ATTRIBUTE_GROUPS(mgb4_gmsl_out); + +static const struct mgb4_vout_config vout_cfg[] = { + {0, 0, 8, {0x78, 0x60, 0x64, 0x68, 0x74, 0x6C, 0x70, 0x7c}}, + {1, 1, 9, {0x98, 0x80, 0x84, 0x88, 0x94, 0x8c, 0x90, 0x9c}} +}; + +static const struct i2c_board_info fpdl3_ser_info[] = { + {I2C_BOARD_INFO("serializer1", 0x14)}, + {I2C_BOARD_INFO("serializer2", 0x16)}, +}; + +static const struct mgb4_i2c_kv fpdl3_i2c[] = { + {0x05, 0xFF, 0x04}, {0x06, 0xFF, 0x01}, {0xC2, 0xFF, 0x80} +}; + +static void return_all_buffers(struct mgb4_vout_dev *voutdev, + enum vb2_buffer_state state) +{ + struct mgb4_frame_buffer *buf, *node; + unsigned long flags; + + spin_lock_irqsave(&voutdev->qlock, flags); + list_for_each_entry_safe(buf, node, &voutdev->buf_list, list) { + vb2_buffer_done(&buf->vb.vb2_buf, state); + list_del(&buf->list); + } + spin_unlock_irqrestore(&voutdev->qlock, flags); +} + +static int queue_setup(struct vb2_queue *q, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct mgb4_vout_dev *voutdev = vb2_get_drv_priv(q); + unsigned int size; + + /* + * If I/O reconfiguration is in process, do not allow to start + * the queue. See video_source_store() in mgb4_sysfs_out.c for + * details. + */ + if (test_bit(0, &voutdev->mgbdev->io_reconfig)) + return -EBUSY; + + size = (voutdev->width + voutdev->padding) * voutdev->height * 4; + + if (*nplanes) + return sizes[0] < size ? -EINVAL : 0; + *nplanes = 1; + sizes[0] = size; + + return 0; +} + +static int buffer_init(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct mgb4_frame_buffer *buf = to_frame_buffer(vbuf); + + INIT_LIST_HEAD(&buf->list); + + return 0; +} + +static int buffer_prepare(struct vb2_buffer *vb) +{ + struct mgb4_vout_dev *voutdev = vb2_get_drv_priv(vb->vb2_queue); + struct device *dev = &voutdev->mgbdev->pdev->dev; + unsigned int size; + + size = (voutdev->width + voutdev->padding) * voutdev->height * 4; + + if (vb2_plane_size(vb, 0) < size) { + dev_err(dev, "buffer too small (%lu < %u)\n", + vb2_plane_size(vb, 0), size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, size); + + return 0; +} + +static void buffer_queue(struct vb2_buffer *vb) +{ + struct mgb4_vout_dev *vindev = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct mgb4_frame_buffer *buf = to_frame_buffer(vbuf); + unsigned long flags; + + spin_lock_irqsave(&vindev->qlock, flags); + list_add_tail(&buf->list, &vindev->buf_list); + spin_unlock_irqrestore(&vindev->qlock, flags); +} + +static void stop_streaming(struct vb2_queue *vq) +{ + struct mgb4_vout_dev *voutdev = vb2_get_drv_priv(vq); + struct mgb4_dev *mgbdev = voutdev->mgbdev; + int irq = xdma_get_user_irq(mgbdev->xdev, voutdev->config->irq); + + xdma_disable_user_irq(mgbdev->xdev, irq); + cancel_work_sync(&voutdev->dma_work); + mgb4_mask_reg(&mgbdev->video, voutdev->config->regs.config, 0x2, 0x0); + return_all_buffers(voutdev, VB2_BUF_STATE_ERROR); +} + +static int start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct mgb4_vout_dev *voutdev = vb2_get_drv_priv(vq); + struct mgb4_dev *mgbdev = voutdev->mgbdev; + struct device *dev = &mgbdev->pdev->dev; + struct mgb4_frame_buffer *buf; + struct mgb4_regs *video = &mgbdev->video; + const struct mgb4_vout_config *config = voutdev->config; + int irq = xdma_get_user_irq(mgbdev->xdev, config->irq); + int rv; + u32 addr; + + mgb4_mask_reg(video, config->regs.config, 0x2, 0x2); + + addr = mgb4_read_reg(video, config->regs.address); + if (addr >= MGB4_ERR_QUEUE_FULL) { + dev_dbg(dev, "frame queue error (%d)\n", (int)addr); + return_all_buffers(voutdev, VB2_BUF_STATE_QUEUED); + return -EBUSY; + } + + buf = list_first_entry(&voutdev->buf_list, struct mgb4_frame_buffer, + list); + list_del_init(voutdev->buf_list.next); + + rv = mgb4_dma_transfer(mgbdev, config->dma_channel, true, addr, + vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0)); + if (rv < 0) { + dev_warn(dev, "DMA transfer error\n"); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } else { + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + } + + xdma_enable_user_irq(mgbdev->xdev, irq); + + return 0; +} + +static const struct vb2_ops queue_ops = { + .queue_setup = queue_setup, + .buf_init = buffer_init, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .start_streaming = start_streaming, + .stop_streaming = stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish +}; + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); + strscpy(cap->card, "MGB4 PCIe Card", sizeof(cap->card)); + + return 0; +} + +static int vidioc_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index != 0) + return -EINVAL; + + f->pixelformat = V4L2_PIX_FMT_ABGR32; + + return 0; +} + +static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct mgb4_vout_dev *voutdev = video_drvdata(file); + + f->fmt.pix.pixelformat = V4L2_PIX_FMT_ABGR32; + f->fmt.pix.width = voutdev->width; + f->fmt.pix.height = voutdev->height; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW; + f->fmt.pix.bytesperline = (f->fmt.pix.width + voutdev->padding) * 4; + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; + + return 0; +} + +static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct mgb4_vout_dev *voutdev = video_drvdata(file); + + f->fmt.pix.pixelformat = V4L2_PIX_FMT_ABGR32; + f->fmt.pix.width = voutdev->width; + f->fmt.pix.height = voutdev->height; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW; + f->fmt.pix.bytesperline = max(f->fmt.pix.width * 4, + ALIGN_DOWN(f->fmt.pix.bytesperline, 4)); + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; + + return 0; +} + +static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct mgb4_vout_dev *voutdev = video_drvdata(file); + struct mgb4_regs *video = &voutdev->mgbdev->video; + + if (vb2_is_busy(&voutdev->queue)) + return -EBUSY; + + vidioc_try_fmt(file, priv, f); + + voutdev->padding = (f->fmt.pix.bytesperline - (f->fmt.pix.width * 4)) / 4; + mgb4_write_reg(video, voutdev->config->regs.padding, voutdev->padding); + + return 0; +} + +static int vidioc_g_output(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_output(struct file *file, void *priv, unsigned int i) +{ + return i ? -EINVAL : 0; +} + +static int vidioc_enum_output(struct file *file, void *priv, + struct v4l2_output *out) +{ + if (out->index != 0) + return -EINVAL; + + out->type = V4L2_OUTPUT_TYPE_ANALOG; + strscpy(out->name, "MGB4", sizeof(out->name)); + + return 0; +} + +static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt, + .vidioc_try_fmt_vid_out = vidioc_try_fmt, + .vidioc_s_fmt_vid_out = vidioc_s_fmt, + .vidioc_g_fmt_vid_out = vidioc_g_fmt, + .vidioc_enum_output = vidioc_enum_output, + .vidioc_g_output = vidioc_g_output, + .vidioc_s_output = vidioc_s_output, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +static int fh_open(struct file *file) +{ + struct mgb4_vout_dev *voutdev = video_drvdata(file); + struct mgb4_regs *video = &voutdev->mgbdev->video; + struct device *dev = &voutdev->mgbdev->pdev->dev; + u32 config, resolution; + int rv; + + /* Return EBUSY when the device is in loopback mode */ + config = mgb4_read_reg(video, voutdev->config->regs.config); + if ((config & 0xc) >> 2 != voutdev->config->id + MGB4_VIN_DEVICES) { + dev_dbg(dev, "can not open - device in loopback mode"); + return -EBUSY; + } + + mutex_lock(&voutdev->lock); + + rv = v4l2_fh_open(file); + if (rv) + goto out; + + if (!v4l2_fh_is_singular_file(file)) + goto out; + + resolution = mgb4_read_reg(video, voutdev->config->regs.resolution); + voutdev->width = resolution >> 16; + voutdev->height = resolution & 0xFFFF; + +out: + mutex_unlock(&voutdev->lock); + return rv; +} + +static const struct v4l2_file_operations video_fops = { + .owner = THIS_MODULE, + .open = fh_open, + .release = vb2_fop_release, + .unlocked_ioctl = video_ioctl2, + .write = vb2_fop_write, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, +}; + +static void dma_transfer(struct work_struct *work) +{ + struct mgb4_vout_dev *voutdev = container_of(work, struct mgb4_vout_dev, + dma_work); + struct device *dev = &voutdev->mgbdev->pdev->dev; + struct mgb4_regs *video = &voutdev->mgbdev->video; + struct mgb4_frame_buffer *buf = NULL; + unsigned long flags; + u32 addr; + int rv; + + spin_lock_irqsave(&voutdev->qlock, flags); + if (!list_empty(&voutdev->buf_list)) { + buf = list_first_entry(&voutdev->buf_list, + struct mgb4_frame_buffer, list); + list_del_init(voutdev->buf_list.next); + } + spin_unlock_irqrestore(&voutdev->qlock, flags); + + if (!buf) + return; + + addr = mgb4_read_reg(video, voutdev->config->regs.address); + if (addr >= MGB4_ERR_QUEUE_FULL) { + dev_dbg(dev, "frame queue error (%d)\n", (int)addr); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + return; + } + + rv = mgb4_dma_transfer(voutdev->mgbdev, voutdev->config->dma_channel, + true, addr, + vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0)); + if (rv < 0) { + dev_warn(dev, "DMA transfer error\n"); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } else { + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + } +} + +static irqreturn_t handler(int irq, void *ctx) +{ + struct mgb4_vout_dev *voutdev = (struct mgb4_vout_dev *)ctx; + struct mgb4_regs *video = &voutdev->mgbdev->video; + + schedule_work(&voutdev->dma_work); + + mgb4_write_reg(video, 0xB4, 1U << voutdev->config->irq); + + return IRQ_HANDLED; +} + +static int ser_init(struct mgb4_vout_dev *voutdev, int id) +{ + int rv; + const struct i2c_board_info *info = &fpdl3_ser_info[id]; + struct mgb4_i2c_client *ser = &voutdev->ser; + struct device *dev = &voutdev->mgbdev->pdev->dev; + + if (MGB4_IS_GMSL(voutdev->mgbdev)) + return 0; + + rv = mgb4_i2c_init(ser, voutdev->mgbdev->i2c_adap, info, 8); + if (rv < 0) { + dev_err(dev, "failed to create serializer\n"); + return rv; + } + rv = mgb4_i2c_configure(ser, fpdl3_i2c, ARRAY_SIZE(fpdl3_i2c)); + if (rv < 0) { + dev_err(dev, "failed to configure serializer\n"); + goto err_i2c_dev; + } + + return 0; + +err_i2c_dev: + mgb4_i2c_free(ser); + + return rv; +} + +static void fpga_init(struct mgb4_vout_dev *voutdev) +{ + struct mgb4_regs *video = &voutdev->mgbdev->video; + const struct mgb4_vout_regs *regs = &voutdev->config->regs; + + mgb4_write_reg(video, regs->config, 0x00000011); + mgb4_write_reg(video, regs->resolution, + (MGB4_DEFAULT_WIDTH << 16) | MGB4_DEFAULT_HEIGHT); + mgb4_write_reg(video, regs->hsync, 0x00102020); + mgb4_write_reg(video, regs->vsync, 0x40020202); + mgb4_write_reg(video, regs->frame_period, MGB4_DEFAULT_PERIOD); + mgb4_write_reg(video, regs->padding, 0x00000000); + + voutdev->freq = mgb4_cmt_set_vout_freq(voutdev, 70000 >> 1) << 1; + + mgb4_write_reg(video, regs->config, + (voutdev->config->id + MGB4_VIN_DEVICES) << 2 | 1 << 4); +} + +#ifdef CONFIG_DEBUG_FS +static void debugfs_init(struct mgb4_vout_dev *voutdev) +{ + struct mgb4_regs *video = &voutdev->mgbdev->video; + + voutdev->debugfs = debugfs_create_dir(voutdev->vdev.name, + voutdev->mgbdev->debugfs); + if (!voutdev->debugfs) + return; + + voutdev->regs[0].name = "CONFIG"; + voutdev->regs[0].offset = voutdev->config->regs.config; + voutdev->regs[1].name = "STATUS"; + voutdev->regs[1].offset = voutdev->config->regs.status; + voutdev->regs[2].name = "RESOLUTION"; + voutdev->regs[2].offset = voutdev->config->regs.resolution; + voutdev->regs[3].name = "VIDEO_PARAMS_1"; + voutdev->regs[3].offset = voutdev->config->regs.hsync; + voutdev->regs[4].name = "VIDEO_PARAMS_2"; + voutdev->regs[4].offset = voutdev->config->regs.vsync; + voutdev->regs[5].name = "FRAME_PERIOD"; + voutdev->regs[5].offset = voutdev->config->regs.frame_period; + voutdev->regs[6].name = "PADDING"; + voutdev->regs[6].offset = voutdev->config->regs.padding; + + voutdev->regset.base = video->membase; + voutdev->regset.regs = voutdev->regs; + voutdev->regset.nregs = ARRAY_SIZE(voutdev->regs); + + debugfs_create_regset32("registers", 0444, voutdev->debugfs, + &voutdev->regset); +} +#endif + +struct mgb4_vout_dev *mgb4_vout_create(struct mgb4_dev *mgbdev, int id) +{ + int rv, irq; + const struct attribute_group **groups; + struct mgb4_vout_dev *voutdev; + struct pci_dev *pdev = mgbdev->pdev; + struct device *dev = &pdev->dev; + + voutdev = kzalloc(sizeof(*voutdev), GFP_KERNEL); + if (!voutdev) + return NULL; + + voutdev->mgbdev = mgbdev; + voutdev->config = &vout_cfg[id]; + + /* Frame queue */ + INIT_LIST_HEAD(&voutdev->buf_list); + spin_lock_init(&voutdev->qlock); + + /* DMA transfer stuff */ + INIT_WORK(&voutdev->dma_work, dma_transfer); + + /* IRQ callback */ + irq = xdma_get_user_irq(mgbdev->xdev, voutdev->config->irq); + rv = request_irq(irq, handler, 0, "mgb4-vout", voutdev); + if (rv) { + dev_err(dev, "failed to register irq handler\n"); + goto err_alloc; + } + + /* Set the FPGA registers default values */ + fpga_init(voutdev); + + /* Set the serializer default values */ + rv = ser_init(voutdev, id); + if (rv) + goto err_irq; + + /* V4L2 stuff init */ + rv = v4l2_device_register(dev, &voutdev->v4l2dev); + if (rv) { + dev_err(dev, "failed to register v4l2 device\n"); + goto err_irq; + } + + mutex_init(&voutdev->lock); + + voutdev->queue.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + voutdev->queue.io_modes = VB2_MMAP | VB2_DMABUF | VB2_WRITE; + voutdev->queue.buf_struct_size = sizeof(struct mgb4_frame_buffer); + voutdev->queue.ops = &queue_ops; + voutdev->queue.mem_ops = &vb2_dma_sg_memops; + voutdev->queue.gfp_flags = GFP_DMA32; + voutdev->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + voutdev->queue.min_buffers_needed = 2; + voutdev->queue.drv_priv = voutdev; + voutdev->queue.lock = &voutdev->lock; + voutdev->queue.dev = dev; + rv = vb2_queue_init(&voutdev->queue); + if (rv) { + dev_err(dev, "failed to initialize vb2 queue\n"); + goto err_v4l2_dev; + } + + snprintf(voutdev->vdev.name, sizeof(voutdev->vdev.name), "mgb4-out%d", + id + 1); + voutdev->vdev.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE + | V4L2_CAP_STREAMING; + voutdev->vdev.vfl_dir = VFL_DIR_TX; + voutdev->vdev.fops = &video_fops; + voutdev->vdev.ioctl_ops = &video_ioctl_ops; + voutdev->vdev.release = video_device_release_empty; + voutdev->vdev.v4l2_dev = &voutdev->v4l2dev; + voutdev->vdev.lock = &voutdev->lock; + voutdev->vdev.queue = &voutdev->queue; + video_set_drvdata(&voutdev->vdev, voutdev); + + rv = video_register_device(&voutdev->vdev, VFL_TYPE_VIDEO, -1); + if (rv) { + dev_err(dev, "failed to register video device\n"); + goto err_v4l2_dev; + } + + /* Module sysfs attributes */ + groups = MGB4_IS_GMSL(mgbdev) + ? mgb4_gmsl_out_groups : mgb4_fpdl3_out_groups; + rv = device_add_groups(&voutdev->vdev.dev, groups); + if (rv) { + dev_err(dev, "failed to create sysfs attributes\n"); + goto err_video_dev; + } + +#ifdef CONFIG_DEBUG_FS + debugfs_init(voutdev); +#endif + + return voutdev; + +err_video_dev: + video_unregister_device(&voutdev->vdev); +err_v4l2_dev: + v4l2_device_unregister(&voutdev->v4l2dev); +err_irq: + free_irq(irq, voutdev); +err_alloc: + kfree(voutdev); + + return NULL; +} + +void mgb4_vout_free(struct mgb4_vout_dev *voutdev) +{ + const struct attribute_group **groups; + int irq = xdma_get_user_irq(voutdev->mgbdev->xdev, voutdev->config->irq); + + free_irq(irq, voutdev); + +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(voutdev->debugfs); +#endif + + groups = MGB4_IS_GMSL(voutdev->mgbdev) + ? mgb4_gmsl_out_groups : mgb4_fpdl3_out_groups; + device_remove_groups(&voutdev->vdev.dev, groups); + + mgb4_i2c_free(&voutdev->ser); + video_unregister_device(&voutdev->vdev); + v4l2_device_unregister(&voutdev->v4l2dev); + + kfree(voutdev); +} diff --git a/drivers/media/pci/mgb4/mgb4_vout.h b/drivers/media/pci/mgb4/mgb4_vout.h new file mode 100644 index 0000000000000..b163dee711fde --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_vout.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma + */ + +#ifndef __MGB4_VOUT_H__ +#define __MGB4_VOUT_H__ + +#include +#include +#include +#include +#include +#include "mgb4_i2c.h" + +struct mgb4_vout_regs { + u32 address; + u32 config; + u32 status; + u32 resolution; + u32 frame_period; + u32 hsync; + u32 vsync; + u32 padding; +}; + +struct mgb4_vout_config { + int id; + int dma_channel; + int irq; + struct mgb4_vout_regs regs; +}; + +struct mgb4_vout_dev { + struct mgb4_dev *mgbdev; + struct v4l2_device v4l2dev; + struct video_device vdev; + struct vb2_queue queue; + struct mutex lock; /* vdev lock */ + + spinlock_t qlock; /* buffer queue lock */ + struct list_head buf_list; + struct work_struct dma_work; + + u32 width; + u32 height; + u32 freq; + u32 padding; + + struct mgb4_i2c_client ser; + + const struct mgb4_vout_config *config; + +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs; + struct debugfs_regset32 regset; + struct debugfs_reg32 regs[7]; +#endif +}; + +struct mgb4_vout_dev *mgb4_vout_create(struct mgb4_dev *mgbdev, int id); +void mgb4_vout_free(struct mgb4_vout_dev *voutdev); + +#endif -- GitLab From bd7e2477d737ab78276f9a7369a5d71ca8dd4446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Mon, 25 Sep 2023 16:36:05 +0200 Subject: [PATCH 0424/1451] media: Documentation: Added Digiteq Automotive MGB4 driver documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "admin-guide" documentation for the Digiteq Automotive MGB4 driver. Signed-off-by: Martin Tůma Signed-off-by: Hans Verkuil --- Documentation/admin-guide/media/mgb4.rst | 374 ++++++++++++++++++ .../admin-guide/media/pci-cardlist.rst | 1 + .../admin-guide/media/v4l-drivers.rst | 1 + 3 files changed, 376 insertions(+) create mode 100644 Documentation/admin-guide/media/mgb4.rst diff --git a/Documentation/admin-guide/media/mgb4.rst b/Documentation/admin-guide/media/mgb4.rst new file mode 100644 index 0000000000000..2977f74d7e267 --- /dev/null +++ b/Documentation/admin-guide/media/mgb4.rst @@ -0,0 +1,374 @@ +.. SPDX-License-Identifier: GPL-2.0 + +==================== +mgb4 sysfs interface +==================== + +The mgb4 driver provides a sysfs interface, that is used to configure video +stream related parameters (some of them must be set properly before the v4l2 +device can be opened) and obtain the video device/stream status. + +There are two types of parameters - global / PCI card related, found under +``/sys/class/video4linux/videoX/device`` and module specific found under +``/sys/class/video4linux/videoX``. + + +Global (PCI card) parameters +============================ + +**module_type** (R): + Module type. + + | 0 - No module present + | 1 - FPDL3 + | 2 - GMSL + +**module_version** (R): + Module version number. Zero in case of a missing module. + +**fw_type** (R): + Firmware type. + + | 1 - FPDL3 + | 2 - GMSL + +**fw_version** (R): + Firmware version number. + +**serial_number** (R): + Card serial number. The format is:: + + PRODUCT-REVISION-SERIES-SERIAL + + where each component is a 8b number. + + +Common FPDL3/GMSL input parameters +================================== + +**input_id** (R): + Input number ID, zero based. + +**oldi_lane_width** (RW): + Number of deserializer output lanes. + + | 0 - single + | 1 - dual (default) + +**color_mapping** (RW): + Mapping of the incoming bits in the signal to the colour bits of the pixels. + + | 0 - OLDI/JEIDA + | 1 - SPWG/VESA (default) + +**link_status** (R): + Video link status. If the link is locked, chips are properly connected and + communicating at the same speed and protocol. The link can be locked without + an active video stream. + + A value of 0 is equivalent to the V4L2_IN_ST_NO_SYNC flag of the V4L2 + VIDIOC_ENUMINPUT status bits. + + | 0 - unlocked + | 1 - locked + +**stream_status** (R): + Video stream status. A stream is detected if the link is locked, the input + pixel clock is running and the DE signal is moving. + + A value of 0 is equivalent to the V4L2_IN_ST_NO_SIGNAL flag of the V4L2 + VIDIOC_ENUMINPUT status bits. + + | 0 - not detected + | 1 - detected + +**video_width** (R): + Video stream width. This is the actual width as detected by the HW. + + The value is identical to what VIDIOC_QUERY_DV_TIMINGS returns in the width + field of the v4l2_bt_timings struct. + +**video_height** (R): + Video stream height. This is the actual height as detected by the HW. + + The value is identical to what VIDIOC_QUERY_DV_TIMINGS returns in the height + field of the v4l2_bt_timings struct. + +**vsync_status** (R): + The type of VSYNC pulses as detected by the video format detector. + + The value is equivalent to the flags returned by VIDIOC_QUERY_DV_TIMINGS in + the polarities field of the v4l2_bt_timings struct. + + | 0 - active low + | 1 - active high + | 2 - not available + +**hsync_status** (R): + The type of HSYNC pulses as detected by the video format detector. + + The value is equivalent to the flags returned by VIDIOC_QUERY_DV_TIMINGS in + the polarities field of the v4l2_bt_timings struct. + + | 0 - active low + | 1 - active high + | 2 - not available + +**vsync_gap_length** (RW): + If the incoming video signal does not contain synchronization VSYNC and + HSYNC pulses, these must be generated internally in the FPGA to achieve + the correct frame ordering. This value indicates, how many "empty" pixels + (pixels with deasserted Data Enable signal) are necessary to generate the + internal VSYNC pulse. + +**hsync_gap_length** (RW): + If the incoming video signal does not contain synchronization VSYNC and + HSYNC pulses, these must be generated internally in the FPGA to achieve + the correct frame ordering. This value indicates, how many "empty" pixels + (pixels with deasserted Data Enable signal) are necessary to generate the + internal HSYNC pulse. The value must be greater than 1 and smaller than + vsync_gap_length. + +**pclk_frequency** (R): + Input pixel clock frequency in kHz. + + The value is identical to what VIDIOC_QUERY_DV_TIMINGS returns in + the pixelclock field of the v4l2_bt_timings struct. + + *Note: The frequency_range parameter must be set properly first to get + a valid frequency here.* + +**hsync_width** (R): + Width of the HSYNC signal in PCLK clock ticks. + + The value is identical to what VIDIOC_QUERY_DV_TIMINGS returns in + the hsync field of the v4l2_bt_timings struct. + +**vsync_width** (R): + Width of the VSYNC signal in PCLK clock ticks. + + The value is identical to what VIDIOC_QUERY_DV_TIMINGS returns in + the vsync field of the v4l2_bt_timings struct. + +**hback_porch** (R): + Number of PCLK pulses between deassertion of the HSYNC signal and the first + valid pixel in the video line (marked by DE=1). + + The value is identical to what VIDIOC_QUERY_DV_TIMINGS returns in + the hbackporch field of the v4l2_bt_timings struct. + +**hfront_porch** (R): + Number of PCLK pulses between the end of the last valid pixel in the video + line (marked by DE=1) and assertion of the HSYNC signal. + + The value is identical to what VIDIOC_QUERY_DV_TIMINGS returns in + the hfrontporch field of the v4l2_bt_timings struct. + +**vback_porch** (R): + Number of video lines between deassertion of the VSYNC signal and the video + line with the first valid pixel (marked by DE=1). + + The value is identical to what VIDIOC_QUERY_DV_TIMINGS returns in + the vbackporch field of the v4l2_bt_timings struct. + +**vfront_porch** (R): + Number of video lines between the end of the last valid pixel line (marked + by DE=1) and assertion of the VSYNC signal. + + The value is identical to what VIDIOC_QUERY_DV_TIMINGS returns in + the vfrontporch field of the v4l2_bt_timings struct. + +**frequency_range** (RW) + PLL frequency range of the OLDI input clock generator. The PLL frequency is + derived from the Pixel Clock Frequency (PCLK) and is equal to PCLK if + oldi_lane_width is set to "single" and PCLK/2 if oldi_lane_width is set to + "dual". + + | 0 - PLL < 50MHz (default) + | 1 - PLL >= 50MHz + + *Note: This parameter can not be changed while the input v4l2 device is + open.* + + +Common FPDL3/GMSL output parameters +=================================== + +**output_id** (R): + Output number ID, zero based. + +**video_source** (RW): + Output video source. If set to 0 or 1, the source is the corresponding card + input and the v4l2 output devices are disabled. If set to 2 or 3, the source + is the corresponding v4l2 video output device. The default is + the corresponding v4l2 output, i.e. 2 for OUT1 and 3 for OUT2. + + | 0 - input 0 + | 1 - input 1 + | 2 - v4l2 output 0 + | 3 - v4l2 output 1 + + *Note: This parameter can not be changed while ANY of the input/output v4l2 + devices is open.* + +**display_width** (RW): + Display width. There is no autodetection of the connected display, so the + proper value must be set before the start of streaming. The default width + is 1280. + + *Note: This parameter can not be changed while the output v4l2 device is + open.* + +**display_height** (RW): + Display height. There is no autodetection of the connected display, so the + proper value must be set before the start of streaming. The default height + is 640. + + *Note: This parameter can not be changed while the output v4l2 device is + open.* + +**frame_rate** (RW): + Output video frame rate in frames per second. The default frame rate is + 60Hz. + +**hsync_polarity** (RW): + HSYNC signal polarity. + + | 0 - active low (default) + | 1 - active high + +**vsync_polarity** (RW): + VSYNC signal polarity. + + | 0 - active low (default) + | 1 - active high + +**de_polarity** (RW): + DE signal polarity. + + | 0 - active low + | 1 - active high (default) + +**pclk_frequency** (RW): + Output pixel clock frequency. Allowed values are between 25000-190000(kHz) + and there is a non-linear stepping between two consecutive allowed + frequencies. The driver finds the nearest allowed frequency to the given + value and sets it. When reading this property, you get the exact + frequency set by the driver. The default frequency is 70000kHz. + + *Note: This parameter can not be changed while the output v4l2 device is + open.* + +**hsync_width** (RW): + Width of the HSYNC signal in pixels. The default value is 16. + +**vsync_width** (RW): + Width of the VSYNC signal in video lines. The default value is 2. + +**hback_porch** (RW): + Number of PCLK pulses between deassertion of the HSYNC signal and the first + valid pixel in the video line (marked by DE=1). The default value is 32. + +**hfront_porch** (RW): + Number of PCLK pulses between the end of the last valid pixel in the video + line (marked by DE=1) and assertion of the HSYNC signal. The default value + is 32. + +**vback_porch** (RW): + Number of video lines between deassertion of the VSYNC signal and the video + line with the first valid pixel (marked by DE=1). The default value is 2. + +**vfront_porch** (RW): + Number of video lines between the end of the last valid pixel line (marked + by DE=1) and assertion of the VSYNC signal. The default value is 2. + + +FPDL3 specific input parameters +=============================== + +**fpdl3_input_width** (RW): + Number of deserializer input lines. + + | 0 - auto (default) + | 1 - single + | 2 - dual + +FPDL3 specific output parameters +================================ + +**fpdl3_output_width** (RW): + Number of serializer output lines. + + | 0 - auto (default) + | 1 - single + | 2 - dual + +GMSL specific input parameters +============================== + +**gmsl_mode** (RW): + GMSL speed mode. + + | 0 - 12Gb/s (default) + | 1 - 6Gb/s + | 2 - 3Gb/s + | 3 - 1.5Gb/s + +**gmsl_stream_id** (RW): + The GMSL multi-stream contains up to four video streams. This parameter + selects which stream is captured by the video input. The value is the + zero-based index of the stream. The default stream id is 0. + + *Note: This parameter can not be changed while the input v4l2 device is + open.* + +**gmsl_fec** (RW): + GMSL Forward Error Correction (FEC). + + | 0 - disabled + | 1 - enabled (default) + + +==================== +mgb4 mtd partitions +==================== + +The mgb4 driver creates a MTD device with two partitions: + - mgb4-fw.X - FPGA firmware. + - mgb4-data.X - Factory settings, e.g. card serial number. + +The *mgb4-fw* partition is writable and is used for FW updates, *mgb4-data* is +read-only. The *X* attached to the partition name represents the card number. +Depending on the CONFIG_MTD_PARTITIONED_MASTER kernel configuration, you may +also have a third partition named *mgb4-flash* available in the system. This +partition represents the whole, unpartitioned, card's FLASH memory and one should +not fiddle with it... + +==================== +mgb4 iio (triggers) +==================== + +The mgb4 driver creates an Industrial I/O (IIO) device that provides trigger and +signal level status capability. The following scan elements are available: + +**activity**: + The trigger levels and pending status. + + | bit 1 - trigger 1 pending + | bit 2 - trigger 2 pending + | bit 5 - trigger 1 level + | bit 6 - trigger 2 level + +**timestamp**: + The trigger event timestamp. + +The iio device can operate either in "raw" mode where you can fetch the signal +levels (activity bits 5 and 6) using sysfs access or in triggered buffer mode. +In the triggered buffer mode you can follow the signal level changes (activity +bits 1 and 2) using the iio device in /dev. If you enable the timestamps, you +will also get the exact trigger event time that can be matched to a video frame +(every mgb4 video frame has a timestamp with the same clock source). + +*Note: although the activity sample always contains all the status bits, it makes +no sense to get the pending bits in raw mode or the level bits in the triggered +buffer mode - the values do not represent valid data in such case.* diff --git a/Documentation/admin-guide/media/pci-cardlist.rst b/Documentation/admin-guide/media/pci-cardlist.rst index 42528795d4dad..7d8e3c8987dba 100644 --- a/Documentation/admin-guide/media/pci-cardlist.rst +++ b/Documentation/admin-guide/media/pci-cardlist.rst @@ -77,6 +77,7 @@ ipu3-cio2 Intel ipu3-cio2 driver ivtv Conexant cx23416/cx23415 MPEG encoder/decoder ivtvfb Conexant cx23415 framebuffer mantis MANTIS based cards +mgb4 Digiteq Automotive MGB4 frame grabber mxb Siemens-Nixdorf 'Multimedia eXtension Board' netup-unidvb NetUP Universal DVB card ngene Micronas nGene diff --git a/Documentation/admin-guide/media/v4l-drivers.rst b/Documentation/admin-guide/media/v4l-drivers.rst index 1c41f87c39171..61283d67ceefb 100644 --- a/Documentation/admin-guide/media/v4l-drivers.rst +++ b/Documentation/admin-guide/media/v4l-drivers.rst @@ -17,6 +17,7 @@ Video4Linux (V4L) driver-specific documentation imx7 ipu3 ivtv + mgb4 omap3isp omap4_camera philips -- GitLab From 7b5c2ad524f5d4d16fb9fb7ec2ea81bd4d2a6fcb Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Mon, 25 Sep 2023 16:46:51 +0100 Subject: [PATCH 0425/1451] media: qcom: camss: Amalgamate struct resource with struct resource_ispif There is no good reason to differentiate the two resource structures here. As part of a general tidyup of the declaration and passing of resources within in the CAMSS driver it will be advantageous to have one unified resource structure. The two structures are very similar anyway thus leading more credence still to the argument there should be only one. Signed-off-by: Bryan O'Donoghue Acked-by: Konrad Dybcio Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss-ispif.c | 4 ++-- drivers/media/platform/qcom/camss/camss-ispif.h | 4 ++-- drivers/media/platform/qcom/camss/camss.c | 14 +++++++------- drivers/media/platform/qcom/camss/camss.h | 8 +------- 4 files changed, 12 insertions(+), 18 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index 1c7e4b1b49401..61765b874b9a2 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -1095,7 +1095,7 @@ static int ispif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) * Return 0 on success or a negative error code otherwise */ int msm_ispif_subdev_init(struct camss *camss, - const struct resources_ispif *res) + const struct resources *res) { struct device *dev = camss->dev; struct ispif_device *ispif = camss->ispif; @@ -1152,7 +1152,7 @@ int msm_ispif_subdev_init(struct camss *camss, /* Interrupt */ - ret = platform_get_irq_byname(pdev, res->interrupt); + ret = platform_get_irq_byname(pdev, res->interrupt[0]); if (ret < 0) return ret; diff --git a/drivers/media/platform/qcom/camss/camss-ispif.h b/drivers/media/platform/qcom/camss/camss-ispif.h index fdf28e68cc7d8..c7c41f7afcaad 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.h +++ b/drivers/media/platform/qcom/camss/camss-ispif.h @@ -66,10 +66,10 @@ struct ispif_device { struct camss *camss; }; -struct resources_ispif; +struct resources; int msm_ispif_subdev_init(struct camss *camss, - const struct resources_ispif *res); + const struct resources *res); int msm_ispif_register_entities(struct ispif_device *ispif, struct v4l2_device *v4l2_dev); diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index c6df862c79e39..fa0eb30d77c26 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -93,14 +93,14 @@ static const struct resources csid_res_8x16[] = { }, }; -static const struct resources_ispif ispif_res_8x16 = { +static const struct resources ispif_res_8x16 = { /* ISPIF */ .clock = { "top_ahb", "ahb", "ispif_ahb", "csi0", "csi0_pix", "csi0_rdi", "csi1", "csi1_pix", "csi1_rdi" }, .clock_for_reset = { "vfe0", "csi_vfe0" }, .reg = { "ispif", "csi_clk_mux" }, - .interrupt = "ispif" + .interrupt = { "ispif" } }; @@ -234,7 +234,7 @@ static const struct resources csid_res_8x96[] = { } }; -static const struct resources_ispif ispif_res_8x96 = { +static const struct resources ispif_res_8x96 = { /* ISPIF */ .clock = { "top_ahb", "ahb", "ispif_ahb", "csi0", "csi0_pix", "csi0_rdi", @@ -243,7 +243,7 @@ static const struct resources_ispif ispif_res_8x96 = { "csi3", "csi3_pix", "csi3_rdi" }, .clock_for_reset = { "vfe0", "csi_vfe0", "vfe1", "csi_vfe1" }, .reg = { "ispif", "csi_clk_mux" }, - .interrupt = "ispif" + .interrupt = { "ispif" } }; static const struct resources vfe_res_8x96[] = { @@ -410,7 +410,7 @@ static const struct resources csid_res_660[] = { } }; -static const struct resources_ispif ispif_res_660 = { +static const struct resources ispif_res_660 = { /* ISPIF */ .clock = { "top_ahb", "ahb", "ispif_ahb", "csi0", "csi0_pix", "csi0_rdi", @@ -419,7 +419,7 @@ static const struct resources_ispif ispif_res_660 = { "csi3", "csi3_pix", "csi3_rdi" }, .clock_for_reset = { "vfe0", "csi_vfe0", "vfe1", "csi_vfe1" }, .reg = { "ispif", "csi_clk_mux" }, - .interrupt = "ispif" + .interrupt = { "ispif" } }; static const struct resources vfe_res_660[] = { @@ -1122,7 +1122,7 @@ static int camss_init_subdevices(struct camss *camss) { const struct resources *csiphy_res; const struct resources *csid_res; - const struct resources_ispif *ispif_res; + const struct resources *ispif_res; const struct resources *vfe_res; unsigned int i; int ret; diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index f6c326cb853b8..e95211cdb1fd6 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -44,18 +44,12 @@ struct resources { char *regulators[CAMSS_RES_MAX]; char *clock[CAMSS_RES_MAX]; + char *clock_for_reset[CAMSS_RES_MAX]; u32 clock_rate[CAMSS_RES_MAX][CAMSS_RES_MAX]; char *reg[CAMSS_RES_MAX]; char *interrupt[CAMSS_RES_MAX]; }; -struct resources_ispif { - char *clock[CAMSS_RES_MAX]; - char *clock_for_reset[CAMSS_RES_MAX]; - char *reg[CAMSS_RES_MAX]; - char *interrupt; -}; - struct icc_bw_tbl { u32 avg; u32 peak; -- GitLab From 1643b787a2367089148d5577f1bc8db619dc91a1 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Mon, 25 Sep 2023 16:46:52 +0100 Subject: [PATCH 0426/1451] media: qcom: camss: Rename camss struct resources to camss_subdev_resources Rename non-specific struct resources {} to struct camss_subdev_resources {} Each logical block in CAMSS has a number of regulators, clocks and resets associated with it. We represent these blocks as v4l subdevices. The name "struct camss_subdev_resources" is a more descriptive and accurate name. Suggested-by: Laurent Pinchart Signed-off-by: Bryan O'Donoghue Signed-off-by: Hans Verkuil --- .../media/platform/qcom/camss/camss-csid.c | 2 +- .../media/platform/qcom/camss/camss-csid.h | 4 +- .../media/platform/qcom/camss/camss-csiphy.c | 2 +- .../media/platform/qcom/camss/camss-csiphy.h | 4 +- .../media/platform/qcom/camss/camss-ispif.c | 2 +- .../media/platform/qcom/camss/camss-ispif.h | 4 +- drivers/media/platform/qcom/camss/camss-vfe.c | 2 +- drivers/media/platform/qcom/camss/camss-vfe.h | 4 +- drivers/media/platform/qcom/camss/camss.c | 44 +++++++++---------- drivers/media/platform/qcom/camss/camss.h | 2 +- 10 files changed, 35 insertions(+), 35 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index 9d7fb1adebb98..b1113decdb305 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -566,7 +566,7 @@ static const struct v4l2_ctrl_ops csid_ctrl_ops = { * Return 0 on success or a negative error code otherwise */ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, - const struct resources *res, u8 id) + const struct camss_subdev_resources *res, u8 id) { struct device *dev = camss->dev; struct platform_device *pdev = to_platform_device(dev); diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h index d4b48432a0973..30d94eb2eb041 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.h +++ b/drivers/media/platform/qcom/camss/camss-csid.h @@ -172,7 +172,7 @@ struct csid_device { const struct csid_hw_ops *ops; }; -struct resources; +struct camss_subdev_resources; /* * csid_find_code - Find a format code in an array using array index or format code @@ -200,7 +200,7 @@ const struct csid_format *csid_get_fmt_entry(const struct csid_format *formats, u32 code); int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, - const struct resources *res, u8 id); + const struct camss_subdev_resources *res, u8 id); int msm_csid_register_entity(struct csid_device *csid, struct v4l2_device *v4l2_dev); diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index c5ae9c61ee0b1..b1b6c4cf18385 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -546,7 +546,7 @@ static int csiphy_init_formats(struct v4l2_subdev *sd, */ int msm_csiphy_subdev_init(struct camss *camss, struct csiphy_device *csiphy, - const struct resources *res, u8 id) + const struct camss_subdev_resources *res, u8 id) { struct device *dev = camss->dev; struct platform_device *pdev = to_platform_device(dev); diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.h b/drivers/media/platform/qcom/camss/camss-csiphy.h index 1c14947f92d35..c9b7fe82b1f0d 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.h +++ b/drivers/media/platform/qcom/camss/camss-csiphy.h @@ -83,11 +83,11 @@ struct csiphy_device { unsigned int nformats; }; -struct resources; +struct camss_subdev_resources; int msm_csiphy_subdev_init(struct camss *camss, struct csiphy_device *csiphy, - const struct resources *res, u8 id); + const struct camss_subdev_resources *res, u8 id); int msm_csiphy_register_entity(struct csiphy_device *csiphy, struct v4l2_device *v4l2_dev); diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index 61765b874b9a2..75b8a60806b22 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -1095,7 +1095,7 @@ static int ispif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) * Return 0 on success or a negative error code otherwise */ int msm_ispif_subdev_init(struct camss *camss, - const struct resources *res) + const struct camss_subdev_resources *res) { struct device *dev = camss->dev; struct ispif_device *ispif = camss->ispif; diff --git a/drivers/media/platform/qcom/camss/camss-ispif.h b/drivers/media/platform/qcom/camss/camss-ispif.h index c7c41f7afcaad..dff6d5b35c72e 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.h +++ b/drivers/media/platform/qcom/camss/camss-ispif.h @@ -66,10 +66,10 @@ struct ispif_device { struct camss *camss; }; -struct resources; +struct camss_subdev_resources; int msm_ispif_subdev_init(struct camss *camss, - const struct resources *res); + const struct camss_subdev_resources *res); int msm_ispif_register_entities(struct ispif_device *ispif, struct v4l2_device *v4l2_dev); diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index b021f81cef123..e84dcf0f4b2da 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -1279,7 +1279,7 @@ static int vfe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) * Return 0 on success or a negative error code otherwise */ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, - const struct resources *res, u8 id) + const struct camss_subdev_resources *res, u8 id) { struct device *dev = camss->dev; struct platform_device *pdev = to_platform_device(dev); diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index cbc314c4e244b..b4bae9f65c68f 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -153,10 +153,10 @@ struct vfe_device { struct camss_video_ops video_ops; }; -struct resources; +struct camss_subdev_resources; int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, - const struct resources *res, u8 id); + const struct camss_subdev_resources *res, u8 id); int msm_vfe_register_entities(struct vfe_device *vfe, struct v4l2_device *v4l2_dev); diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index fa0eb30d77c26..718ef8e4f5938 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -31,7 +31,7 @@ #define CAMSS_CLOCK_MARGIN_NUMERATOR 105 #define CAMSS_CLOCK_MARGIN_DENOMINATOR 100 -static const struct resources csiphy_res_8x16[] = { +static const struct camss_subdev_resources csiphy_res_8x16[] = { /* CSIPHY0 */ { .regulators = {}, @@ -57,7 +57,7 @@ static const struct resources csiphy_res_8x16[] = { } }; -static const struct resources csid_res_8x16[] = { +static const struct camss_subdev_resources csid_res_8x16[] = { /* CSID0 */ { .regulators = { "vdda" }, @@ -93,7 +93,7 @@ static const struct resources csid_res_8x16[] = { }, }; -static const struct resources ispif_res_8x16 = { +static const struct camss_subdev_resources ispif_res_8x16 = { /* ISPIF */ .clock = { "top_ahb", "ahb", "ispif_ahb", "csi0", "csi0_pix", "csi0_rdi", @@ -104,7 +104,7 @@ static const struct resources ispif_res_8x16 = { }; -static const struct resources vfe_res_8x16[] = { +static const struct camss_subdev_resources vfe_res_8x16[] = { /* VFE0 */ { .regulators = {}, @@ -126,7 +126,7 @@ static const struct resources vfe_res_8x16[] = { } }; -static const struct resources csiphy_res_8x96[] = { +static const struct camss_subdev_resources csiphy_res_8x96[] = { /* CSIPHY0 */ { .regulators = {}, @@ -164,7 +164,7 @@ static const struct resources csiphy_res_8x96[] = { } }; -static const struct resources csid_res_8x96[] = { +static const struct camss_subdev_resources csid_res_8x96[] = { /* CSID0 */ { .regulators = { "vdda" }, @@ -234,7 +234,7 @@ static const struct resources csid_res_8x96[] = { } }; -static const struct resources ispif_res_8x96 = { +static const struct camss_subdev_resources ispif_res_8x96 = { /* ISPIF */ .clock = { "top_ahb", "ahb", "ispif_ahb", "csi0", "csi0_pix", "csi0_rdi", @@ -246,7 +246,7 @@ static const struct resources ispif_res_8x96 = { .interrupt = { "ispif" } }; -static const struct resources vfe_res_8x96[] = { +static const struct camss_subdev_resources vfe_res_8x96[] = { /* VFE0 */ { .regulators = {}, @@ -284,7 +284,7 @@ static const struct resources vfe_res_8x96[] = { } }; -static const struct resources csiphy_res_660[] = { +static const struct camss_subdev_resources csiphy_res_660[] = { /* CSIPHY0 */ { .regulators = {}, @@ -328,7 +328,7 @@ static const struct resources csiphy_res_660[] = { } }; -static const struct resources csid_res_660[] = { +static const struct camss_subdev_resources csid_res_660[] = { /* CSID0 */ { .regulators = { "vdda", "vdd_sec" }, @@ -410,7 +410,7 @@ static const struct resources csid_res_660[] = { } }; -static const struct resources ispif_res_660 = { +static const struct camss_subdev_resources ispif_res_660 = { /* ISPIF */ .clock = { "top_ahb", "ahb", "ispif_ahb", "csi0", "csi0_pix", "csi0_rdi", @@ -422,7 +422,7 @@ static const struct resources ispif_res_660 = { .interrupt = { "ispif" } }; -static const struct resources vfe_res_660[] = { +static const struct camss_subdev_resources vfe_res_660[] = { /* VFE0 */ { .regulators = {}, @@ -466,7 +466,7 @@ static const struct resources vfe_res_660[] = { } }; -static const struct resources csiphy_res_845[] = { +static const struct camss_subdev_resources csiphy_res_845[] = { /* CSIPHY0 */ { .regulators = {}, @@ -540,7 +540,7 @@ static const struct resources csiphy_res_845[] = { } }; -static const struct resources csid_res_845[] = { +static const struct camss_subdev_resources csid_res_845[] = { /* CSID0 */ { .regulators = { "vdda-phy", "vdda-pll" }, @@ -602,7 +602,7 @@ static const struct resources csid_res_845[] = { } }; -static const struct resources vfe_res_845[] = { +static const struct camss_subdev_resources vfe_res_845[] = { /* VFE0 */ { .regulators = {}, @@ -663,7 +663,7 @@ static const struct resources vfe_res_845[] = { } }; -static const struct resources csiphy_res_8250[] = { +static const struct camss_subdev_resources csiphy_res_8250[] = { /* CSIPHY0 */ { .regulators = {}, @@ -720,7 +720,7 @@ static const struct resources csiphy_res_8250[] = { } }; -static const struct resources csid_res_8250[] = { +static const struct camss_subdev_resources csid_res_8250[] = { /* CSID0 */ { .regulators = { "vdda-phy", "vdda-pll" }, @@ -769,7 +769,7 @@ static const struct resources csid_res_8250[] = { } }; -static const struct resources vfe_res_8250[] = { +static const struct camss_subdev_resources vfe_res_8250[] = { /* VFE0 */ { .regulators = {}, @@ -1120,10 +1120,10 @@ static int camss_of_parse_ports(struct camss *camss) */ static int camss_init_subdevices(struct camss *camss) { - const struct resources *csiphy_res; - const struct resources *csid_res; - const struct resources *ispif_res; - const struct resources *vfe_res; + const struct camss_subdev_resources *csiphy_res; + const struct camss_subdev_resources *csid_res; + const struct camss_subdev_resources *ispif_res; + const struct camss_subdev_resources *vfe_res; unsigned int i; int ret; diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index e95211cdb1fd6..9d6ba7b17ff02 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -41,7 +41,7 @@ #define CAMSS_RES_MAX 17 -struct resources { +struct camss_subdev_resources { char *regulators[CAMSS_RES_MAX]; char *clock[CAMSS_RES_MAX]; char *clock_for_reset[CAMSS_RES_MAX]; -- GitLab From de98fe8d1c508c9b1ceb7189a9a84e57ba849578 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Mon, 25 Sep 2023 16:46:53 +0100 Subject: [PATCH 0427/1451] media: qcom: camss: Start to move to module compat matched resources There is a lot of unnecessary if/elsing in this code that arguably should never have made it upstream when adding a second let alone subsequent SoC. I'm guilty of not fixing the mess myself when adding in the sm8250. Before adding in any new SoCs or resources lets take the time to cleanup the resource passing. First step is to pass the generic struct camss_resources as a parameter per the compatible list. Subsequent patches will address the other somewhat disparate strutures which we are also doing if/else on and assigning statically. Squashed down a commit to drop useless NULL assignment for ispif resources. Signed-off-by: Bryan O'Donoghue Acked-by: Konrad Dybcio Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss.c | 90 ++++++++++++----------- drivers/media/platform/qcom/camss/camss.h | 8 ++ 2 files changed, 54 insertions(+), 44 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 718ef8e4f5938..8fa5dee75672d 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -1120,47 +1121,13 @@ static int camss_of_parse_ports(struct camss *camss) */ static int camss_init_subdevices(struct camss *camss) { - const struct camss_subdev_resources *csiphy_res; - const struct camss_subdev_resources *csid_res; - const struct camss_subdev_resources *ispif_res; - const struct camss_subdev_resources *vfe_res; + const struct camss_resources *res = camss->res; unsigned int i; int ret; - if (camss->version == CAMSS_8x16) { - csiphy_res = csiphy_res_8x16; - csid_res = csid_res_8x16; - ispif_res = &ispif_res_8x16; - vfe_res = vfe_res_8x16; - } else if (camss->version == CAMSS_8x96) { - csiphy_res = csiphy_res_8x96; - csid_res = csid_res_8x96; - ispif_res = &ispif_res_8x96; - vfe_res = vfe_res_8x96; - } else if (camss->version == CAMSS_660) { - csiphy_res = csiphy_res_660; - csid_res = csid_res_660; - ispif_res = &ispif_res_660; - vfe_res = vfe_res_660; - } else if (camss->version == CAMSS_845) { - csiphy_res = csiphy_res_845; - csid_res = csid_res_845; - /* Titan VFEs don't have an ISPIF */ - ispif_res = NULL; - vfe_res = vfe_res_845; - } else if (camss->version == CAMSS_8250) { - csiphy_res = csiphy_res_8250; - csid_res = csid_res_8250; - /* Titan VFEs don't have an ISPIF */ - ispif_res = NULL; - vfe_res = vfe_res_8250; - } else { - return -EINVAL; - } - for (i = 0; i < camss->csiphy_num; i++) { ret = msm_csiphy_subdev_init(camss, &camss->csiphy[i], - &csiphy_res[i], i); + &res->csiphy_res[i], i); if (ret < 0) { dev_err(camss->dev, "Failed to init csiphy%d sub-device: %d\n", @@ -1172,7 +1139,7 @@ static int camss_init_subdevices(struct camss *camss) /* note: SM8250 requires VFE to be initialized before CSID */ for (i = 0; i < camss->vfe_num + camss->vfe_lite_num; i++) { ret = msm_vfe_subdev_init(camss, &camss->vfe[i], - &vfe_res[i], i); + &res->vfe_res[i], i); if (ret < 0) { dev_err(camss->dev, "Fail to init vfe%d sub-device: %d\n", i, ret); @@ -1182,7 +1149,7 @@ static int camss_init_subdevices(struct camss *camss) for (i = 0; i < camss->csid_num; i++) { ret = msm_csid_subdev_init(camss, &camss->csid[i], - &csid_res[i], i); + &res->csid_res[i], i); if (ret < 0) { dev_err(camss->dev, "Failed to init csid%d sub-device: %d\n", @@ -1191,7 +1158,7 @@ static int camss_init_subdevices(struct camss *camss) } } - ret = msm_ispif_subdev_init(camss, ispif_res); + ret = msm_ispif_subdev_init(camss, res->ispif_res); if (ret < 0) { dev_err(camss->dev, "Failed to init ispif sub-device: %d\n", ret); @@ -1568,6 +1535,8 @@ static int camss_probe(struct platform_device *pdev) if (!camss) return -ENOMEM; + camss->res = of_device_get_match_data(dev); + atomic_set(&camss->ref_count, 0); camss->dev = dev; platform_set_drvdata(pdev, camss); @@ -1742,12 +1711,45 @@ static void camss_remove(struct platform_device *pdev) camss_genpd_cleanup(camss); } +static const struct camss_resources msm8916_resources = { + .csiphy_res = csiphy_res_8x16, + .csid_res = csid_res_8x16, + .ispif_res = &ispif_res_8x16, + .vfe_res = vfe_res_8x16, +}; + +static const struct camss_resources msm8996_resources = { + .csiphy_res = csiphy_res_8x96, + .csid_res = csid_res_8x96, + .ispif_res = &ispif_res_8x96, + .vfe_res = vfe_res_8x96, +}; + +static const struct camss_resources sdm660_resources = { + .csiphy_res = csiphy_res_660, + .csid_res = csid_res_660, + .ispif_res = &ispif_res_660, + .vfe_res = vfe_res_660, +}; + +static const struct camss_resources sdm845_resources = { + .csiphy_res = csiphy_res_845, + .csid_res = csid_res_845, + .vfe_res = vfe_res_845, +}; + +static const struct camss_resources sm8250_resources = { + .csiphy_res = csiphy_res_8250, + .csid_res = csid_res_8250, + .vfe_res = vfe_res_8250, +}; + static const struct of_device_id camss_dt_match[] = { - { .compatible = "qcom,msm8916-camss" }, - { .compatible = "qcom,msm8996-camss" }, - { .compatible = "qcom,sdm660-camss" }, - { .compatible = "qcom,sdm845-camss" }, - { .compatible = "qcom,sm8250-camss" }, + { .compatible = "qcom,msm8916-camss", .data = &msm8916_resources }, + { .compatible = "qcom,msm8996-camss", .data = &msm8996_resources }, + { .compatible = "qcom,sdm660-camss", .data = &sdm660_resources }, + { .compatible = "qcom,sdm845-camss", .data = &sdm845_resources }, + { .compatible = "qcom,sm8250-camss", .data = &sm8250_resources }, { } }; diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index 9d6ba7b17ff02..20c84e8328880 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -79,6 +79,13 @@ enum icc_count { ICC_SM8250_COUNT = 4, }; +struct camss_resources { + const struct camss_subdev_resources *csiphy_res; + const struct camss_subdev_resources *csid_res; + const struct camss_subdev_resources *ispif_res; + const struct camss_subdev_resources *vfe_res; +}; + struct camss { enum camss_version version; struct v4l2_device v4l2_dev; @@ -99,6 +106,7 @@ struct camss { struct device_link **genpd_link; struct icc_path *icc_path[ICC_SM8250_COUNT]; struct icc_bw_tbl icc_bw_tbl[ICC_SM8250_COUNT]; + const struct camss_resources *res; }; struct camss_camera_interface { -- GitLab From 9e0c2597779921c03f6265c1ce45b0121004e301 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Mon, 25 Sep 2023 16:46:54 +0100 Subject: [PATCH 0428/1451] media: qcom: camss: Pass icc bandwidth table as a platform parameter Pass the bandwidth table as a platform parameter not if/else derived pointer to the static table. Signed-off-by: Bryan O'Donoghue Acked-by: Konrad Dybcio Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss.c | 29 +++++++---------------- drivers/media/platform/qcom/camss/camss.h | 3 ++- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 8fa5dee75672d..f502b4d9e07c5 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -1485,21 +1485,15 @@ static int camss_configure_pd(struct camss *camss) static int camss_icc_get(struct camss *camss) { const struct resources_icc *icc_res; - int nbr_icc_paths = 0; int i; - if (camss->version == CAMSS_8250) { - icc_res = &icc_res_sm8250[0]; - nbr_icc_paths = ICC_SM8250_COUNT; - } + icc_res = camss->res->icc_res; - for (i = 0; i < nbr_icc_paths; i++) { + for (i = 0; i < camss->res->icc_path_num; i++) { camss->icc_path[i] = devm_of_icc_get(camss->dev, icc_res[i].name); if (IS_ERR(camss->icc_path[i])) return PTR_ERR(camss->icc_path[i]); - - camss->icc_bw_tbl[i] = icc_res[i].icc_bw_tbl; } return 0; @@ -1742,6 +1736,8 @@ static const struct camss_resources sm8250_resources = { .csiphy_res = csiphy_res_8250, .csid_res = csid_res_8250, .vfe_res = vfe_res_8250, + .icc_res = icc_res_sm8250, + .icc_path_num = ARRAY_SIZE(icc_res_sm8250), }; static const struct of_device_id camss_dt_match[] = { @@ -1758,14 +1754,10 @@ MODULE_DEVICE_TABLE(of, camss_dt_match); static int __maybe_unused camss_runtime_suspend(struct device *dev) { struct camss *camss = dev_get_drvdata(dev); - int nbr_icc_paths = 0; int i; int ret; - if (camss->version == CAMSS_8250) - nbr_icc_paths = ICC_SM8250_COUNT; - - for (i = 0; i < nbr_icc_paths; i++) { + for (i = 0; i < camss->res->icc_path_num; i++) { ret = icc_set_bw(camss->icc_path[i], 0, 0); if (ret) return ret; @@ -1777,17 +1769,14 @@ static int __maybe_unused camss_runtime_suspend(struct device *dev) static int __maybe_unused camss_runtime_resume(struct device *dev) { struct camss *camss = dev_get_drvdata(dev); - int nbr_icc_paths = 0; + const struct resources_icc *icc_res = camss->res->icc_res; int i; int ret; - if (camss->version == CAMSS_8250) - nbr_icc_paths = ICC_SM8250_COUNT; - - for (i = 0; i < nbr_icc_paths; i++) { + for (i = 0; i < camss->res->icc_path_num; i++) { ret = icc_set_bw(camss->icc_path[i], - camss->icc_bw_tbl[i].avg, - camss->icc_bw_tbl[i].peak); + icc_res[i].icc_bw_tbl.avg, + icc_res[i].icc_bw_tbl.peak); if (ret) return ret; } diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index 20c84e8328880..8b2e4adb923ef 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -84,6 +84,8 @@ struct camss_resources { const struct camss_subdev_resources *csid_res; const struct camss_subdev_resources *ispif_res; const struct camss_subdev_resources *vfe_res; + const struct resources_icc *icc_res; + const unsigned int icc_path_num; }; struct camss { @@ -105,7 +107,6 @@ struct camss { struct device **genpd; struct device_link **genpd_link; struct icc_path *icc_path[ICC_SM8250_COUNT]; - struct icc_bw_tbl icc_bw_tbl[ICC_SM8250_COUNT]; const struct camss_resources *res; }; -- GitLab From 5900b051959ebf56eb5c6687d8cafb48fc34b973 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Mon, 25 Sep 2023 16:46:55 +0100 Subject: [PATCH 0429/1451] media: qcom: camss: Pass remainder of variables as resources The following variables are being assigned statically based on compatible strings in the probe path. * enum camss_version version; * unsigned int csiphy_num; * unsigned int csid_num; * unsigned int vfe_num; * unsigned int vfe_lite_num; * unsigned int vfe_total_num; Migrate those variables to resource parameters passed in on platform probe arguments. The one caveat is for VFE it has been necessary to intoduce a new variable vfe_total_num to capture the aggregate value of vfe_num + vfe_lite_num. All the rest of the changes are rote camss->variable to camss->res->variable with the parameter tables now populating the listed variables. Signed-off-by: Bryan O'Donoghue Acked-by: Konrad Dybcio Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- .../media/platform/qcom/camss/camss-csid.c | 14 +-- .../qcom/camss/camss-csiphy-3ph-1-0.c | 8 +- .../media/platform/qcom/camss/camss-csiphy.c | 16 +-- .../media/platform/qcom/camss/camss-ispif.c | 28 ++--- .../media/platform/qcom/camss/camss-vfe-170.c | 4 +- .../media/platform/qcom/camss/camss-vfe-480.c | 4 +- drivers/media/platform/qcom/camss/camss-vfe.c | 26 ++-- .../media/platform/qcom/camss/camss-video.c | 10 +- drivers/media/platform/qcom/camss/camss.c | 115 ++++++++---------- drivers/media/platform/qcom/camss/camss.h | 11 +- 10 files changed, 113 insertions(+), 123 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index b1113decdb305..14abb7a7ceb47 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -159,7 +159,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on) struct camss *camss = csid->camss; struct device *dev = camss->dev; struct vfe_device *vfe = &camss->vfe[csid->id]; - u32 version = camss->version; + u32 version = camss->res->version; int ret = 0; if (on) { @@ -576,13 +576,13 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, csid->camss = camss; csid->id = id; - if (camss->version == CAMSS_8x16) { + if (camss->res->version == CAMSS_8x16) { csid->ops = &csid_ops_4_1; - } else if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) { + } else if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_660) { csid->ops = &csid_ops_4_7; - } else if (camss->version == CAMSS_845 || - camss->version == CAMSS_8250) { + } else if (camss->res->version == CAMSS_845 || + camss->res->version == CAMSS_8250) { csid->ops = &csid_ops_gen2; } else { return -EINVAL; @@ -591,7 +591,7 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, /* Memory */ - if (camss->version == CAMSS_8250) { + if (camss->res->version == CAMSS_8250) { /* for titan 480, CSID registers are inside the VFE region, * between the VFE "top" and "bus" registers. this requires * VFE to be initialized before CSID diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c index 4dba61b8d3f2a..f50e2235c37fc 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c @@ -402,7 +402,7 @@ static void csiphy_gen1_config_lanes(struct csiphy_device *csiphy, val = CSIPHY_3PH_LNn_CFG1_SWI_REC_DLY_PRG; writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_CFG1(l)); - if (csiphy->camss->version == CAMSS_660) + if (csiphy->camss->res->version == CAMSS_660) val = CSIPHY_3PH_LNn_CFG4_T_HS_CLK_MISS_660; else val = CSIPHY_3PH_LNn_CFG4_T_HS_CLK_MISS; @@ -419,7 +419,7 @@ static void csiphy_gen2_config_lanes(struct csiphy_device *csiphy, int i, l, array_size; u32 val; - switch (csiphy->camss->version) { + switch (csiphy->camss->res->version) { case CAMSS_845: r = &lane_regs_sdm845[0][0]; array_size = ARRAY_SIZE(lane_regs_sdm845[0]); @@ -468,8 +468,8 @@ static void csiphy_lanes_enable(struct csiphy_device *csiphy, s64 link_freq, u8 lane_mask) { struct csiphy_lanes_cfg *c = &cfg->csi2->lane_cfg; - bool is_gen2 = (csiphy->camss->version == CAMSS_845 || - csiphy->camss->version == CAMSS_8250); + bool is_gen2 = (csiphy->camss->res->version == CAMSS_845 || + csiphy->camss->res->version == CAMSS_8250); u8 settle_cnt; u8 val; int i; diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index b1b6c4cf18385..48e6a101ec9c9 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -557,17 +557,17 @@ int msm_csiphy_subdev_init(struct camss *camss, csiphy->id = id; csiphy->cfg.combo_mode = 0; - if (camss->version == CAMSS_8x16) { + if (camss->res->version == CAMSS_8x16) { csiphy->ops = &csiphy_ops_2ph_1_0; csiphy->formats = csiphy_formats_8x16; csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x16); - } else if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) { + } else if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_660) { csiphy->ops = &csiphy_ops_3ph_1_0; csiphy->formats = csiphy_formats_8x96; csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x96); - } else if (camss->version == CAMSS_845 || - camss->version == CAMSS_8250) { + } else if (camss->res->version == CAMSS_845 || + camss->res->version == CAMSS_8250) { csiphy->ops = &csiphy_ops_3ph_1_0; csiphy->formats = csiphy_formats_sdm845; csiphy->nformats = ARRAY_SIZE(csiphy_formats_sdm845); @@ -581,8 +581,8 @@ int msm_csiphy_subdev_init(struct camss *camss, if (IS_ERR(csiphy->base)) return PTR_ERR(csiphy->base); - if (camss->version == CAMSS_8x16 || - camss->version == CAMSS_8x96) { + if (camss->res->version == CAMSS_8x16 || + camss->res->version == CAMSS_8x96) { csiphy->base_clk_mux = devm_platform_ioremap_resource_byname(pdev, res->reg[1]); if (IS_ERR(csiphy->base_clk_mux)) @@ -664,7 +664,7 @@ int msm_csiphy_subdev_init(struct camss *camss, !strcmp(clock->name, "csiphy5_timer")) csiphy->rate_set[i] = true; - if (camss->version == CAMSS_660 && + if (camss->res->version == CAMSS_660 && (!strcmp(clock->name, "csi0_phy") || !strcmp(clock->name, "csi1_phy") || !strcmp(clock->name, "csi2_phy"))) diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index 75b8a60806b22..be9d2f0a10c18 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -270,7 +270,7 @@ static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id) unsigned long time; u32 val; - if (vfe_id > (camss->vfe_num - 1)) { + if (vfe_id > camss->res->vfe_num - 1) { dev_err(camss->dev, "Error: asked reset for invalid VFE%d\n", vfe_id); return -ENOENT; @@ -829,8 +829,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable) ispif_select_csid(ispif, intf, csid, vfe, 1); ispif_select_cid(ispif, intf, cid, vfe, 1); ispif_config_irq(ispif, intf, vfe, 1); - if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) + if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_660) ispif_config_pack(ispif, line->fmt[MSM_ISPIF_PAD_SINK].code, intf, cid, vfe, 1); @@ -847,8 +847,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable) return ret; mutex_lock(&ispif->config_lock); - if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) + if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_660) ispif_config_pack(ispif, line->fmt[MSM_ISPIF_PAD_SINK].code, intf, cid, vfe, 0); @@ -1109,10 +1109,10 @@ int msm_ispif_subdev_init(struct camss *camss, ispif->camss = camss; /* Number of ISPIF lines - same as number of CSID hardware modules */ - if (camss->version == CAMSS_8x16) + if (camss->res->version == CAMSS_8x16) ispif->line_num = 2; - else if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) + else if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_660) ispif->line_num = 4; else return -EINVAL; @@ -1126,12 +1126,12 @@ int msm_ispif_subdev_init(struct camss *camss, ispif->line[i].ispif = ispif; ispif->line[i].id = i; - if (camss->version == CAMSS_8x16) { + if (camss->res->version == CAMSS_8x16) { ispif->line[i].formats = ispif_formats_8x16; ispif->line[i].nformats = ARRAY_SIZE(ispif_formats_8x16); - } else if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) { + } else if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_660) { ispif->line[i].formats = ispif_formats_8x96; ispif->line[i].nformats = ARRAY_SIZE(ispif_formats_8x96); @@ -1159,11 +1159,11 @@ int msm_ispif_subdev_init(struct camss *camss, ispif->irq = ret; snprintf(ispif->irq_name, sizeof(ispif->irq_name), "%s_%s", dev_name(dev), MSM_ISPIF_NAME); - if (camss->version == CAMSS_8x16) + if (camss->res->version == CAMSS_8x16) ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x16, IRQF_TRIGGER_RISING, ispif->irq_name, ispif); - else if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) + else if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_660) ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x96, IRQF_TRIGGER_RISING, ispif->irq_name, ispif); else diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c index 168baaa80d4e6..82d2392022dd1 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-170.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c @@ -673,7 +673,7 @@ static void vfe_pm_domain_off(struct vfe_device *vfe) { struct camss *camss = vfe->camss; - if (vfe->id >= camss->vfe_num) + if (vfe->id >= camss->res->vfe_num) return; device_link_del(camss->genpd_link[vfe->id]); @@ -688,7 +688,7 @@ static int vfe_pm_domain_on(struct vfe_device *vfe) struct camss *camss = vfe->camss; enum vfe_line_id id = vfe->id; - if (id >= camss->vfe_num) + if (id >= camss->res->vfe_num) return 0; camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], diff --git a/drivers/media/platform/qcom/camss/camss-vfe-480.c b/drivers/media/platform/qcom/camss/camss-vfe-480.c index 8ddb8016434ae..074fa4e38163e 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-480.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-480.c @@ -499,7 +499,7 @@ static void vfe_pm_domain_off(struct vfe_device *vfe) { struct camss *camss = vfe->camss; - if (vfe->id >= camss->vfe_num) + if (vfe->id >= camss->res->vfe_num) return; device_link_del(camss->genpd_link[vfe->id]); @@ -514,7 +514,7 @@ static int vfe_pm_domain_on(struct vfe_device *vfe) struct camss *camss = vfe->camss; enum vfe_line_id id = vfe->id; - if (id >= camss->vfe_num) + if (id >= camss->res->vfe_num) return 0; camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index e84dcf0f4b2da..94ee7c7039eb3 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -170,7 +170,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, { struct vfe_device *vfe = to_vfe(line); - if (vfe->camss->version == CAMSS_8x16) + if (vfe->camss->res->version == CAMSS_8x16) switch (sink_code) { case MEDIA_BUS_FMT_YUYV8_1X16: { @@ -218,10 +218,10 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, return sink_code; } - else if (vfe->camss->version == CAMSS_8x96 || - vfe->camss->version == CAMSS_660 || - vfe->camss->version == CAMSS_845 || - vfe->camss->version == CAMSS_8250) + else if (vfe->camss->res->version == CAMSS_8x96 || + vfe->camss->res->version == CAMSS_660 || + vfe->camss->res->version == CAMSS_845 || + vfe->camss->res->version == CAMSS_8250) switch (sink_code) { case MEDIA_BUS_FMT_YUYV8_1X16: { @@ -1286,7 +1286,7 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, int i, j; int ret; - switch (camss->version) { + switch (camss->res->version) { case CAMSS_8x16: vfe->ops = &vfe_ops_4_1; break; @@ -1392,7 +1392,7 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, init_completion(&l->output.sof); init_completion(&l->output.reg_update); - if (camss->version == CAMSS_8x16) { + if (camss->res->version == CAMSS_8x16) { if (i == VFE_LINE_PIX) { l->formats = formats_pix_8x16; l->nformats = ARRAY_SIZE(formats_pix_8x16); @@ -1400,8 +1400,8 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, l->formats = formats_rdi_8x16; l->nformats = ARRAY_SIZE(formats_rdi_8x16); } - } else if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) { + } else if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_660) { if (i == VFE_LINE_PIX) { l->formats = formats_pix_8x96; l->nformats = ARRAY_SIZE(formats_pix_8x96); @@ -1409,8 +1409,8 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, l->formats = formats_rdi_8x96; l->nformats = ARRAY_SIZE(formats_rdi_8x96); } - } else if (camss->version == CAMSS_845 || - camss->version == CAMSS_8250) { + } else if (camss->res->version == CAMSS_845 || + camss->res->version == CAMSS_8250) { l->formats = formats_rdi_845; l->nformats = ARRAY_SIZE(formats_rdi_845); } else { @@ -1542,8 +1542,8 @@ int msm_vfe_register_entities(struct vfe_device *vfe, } video_out->ops = &vfe->video_ops; - if (vfe->camss->version == CAMSS_845 || - vfe->camss->version == CAMSS_8250) + if (vfe->camss->res->version == CAMSS_845 || + vfe->camss->res->version == CAMSS_8250) video_out->bpl_alignment = 16; else video_out->bpl_alignment = 8; diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 1d686aef92eaf..46a89b5f6c171 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -1006,7 +1006,7 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, mutex_init(&video->lock); - if (video->camss->version == CAMSS_8x16) { + if (video->camss->res->version == CAMSS_8x16) { if (is_pix) { video->formats = formats_pix_8x16; video->nformats = ARRAY_SIZE(formats_pix_8x16); @@ -1014,8 +1014,8 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, video->formats = formats_rdi_8x16; video->nformats = ARRAY_SIZE(formats_rdi_8x16); } - } else if (video->camss->version == CAMSS_8x96 || - video->camss->version == CAMSS_660) { + } else if (video->camss->res->version == CAMSS_8x96 || + video->camss->res->version == CAMSS_660) { if (is_pix) { video->formats = formats_pix_8x96; video->nformats = ARRAY_SIZE(formats_pix_8x96); @@ -1023,8 +1023,8 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, video->formats = formats_rdi_8x96; video->nformats = ARRAY_SIZE(formats_rdi_8x96); } - } else if (video->camss->version == CAMSS_845 || - video->camss->version == CAMSS_8250) { + } else if (video->camss->res->version == CAMSS_845 || + video->camss->res->version == CAMSS_8250) { video->formats = formats_rdi_845; video->nformats = ARRAY_SIZE(formats_rdi_845); } else { diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index f502b4d9e07c5..d1152a7db9cd2 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -1005,7 +1005,7 @@ int camss_pm_domain_on(struct camss *camss, int id) { int ret = 0; - if (id < camss->vfe_num) { + if (id < camss->res->vfe_num) { struct vfe_device *vfe = &camss->vfe[id]; ret = vfe->ops->pm_domain_on(vfe); @@ -1016,7 +1016,7 @@ int camss_pm_domain_on(struct camss *camss, int id) void camss_pm_domain_off(struct camss *camss, int id) { - if (id < camss->vfe_num) { + if (id < camss->res->vfe_num) { struct vfe_device *vfe = &camss->vfe[id]; vfe->ops->pm_domain_off(vfe); @@ -1125,7 +1125,7 @@ static int camss_init_subdevices(struct camss *camss) unsigned int i; int ret; - for (i = 0; i < camss->csiphy_num; i++) { + for (i = 0; i < camss->res->csiphy_num; i++) { ret = msm_csiphy_subdev_init(camss, &camss->csiphy[i], &res->csiphy_res[i], i); if (ret < 0) { @@ -1137,7 +1137,7 @@ static int camss_init_subdevices(struct camss *camss) } /* note: SM8250 requires VFE to be initialized before CSID */ - for (i = 0; i < camss->vfe_num + camss->vfe_lite_num; i++) { + for (i = 0; i < camss->vfe_total_num; i++) { ret = msm_vfe_subdev_init(camss, &camss->vfe[i], &res->vfe_res[i], i); if (ret < 0) { @@ -1147,7 +1147,7 @@ static int camss_init_subdevices(struct camss *camss) } } - for (i = 0; i < camss->csid_num; i++) { + for (i = 0; i < camss->res->csid_num; i++) { ret = msm_csid_subdev_init(camss, &camss->csid[i], &res->csid_res[i], i); if (ret < 0) { @@ -1179,7 +1179,7 @@ static int camss_register_entities(struct camss *camss) int i, j, k; int ret; - for (i = 0; i < camss->csiphy_num; i++) { + for (i = 0; i < camss->res->csiphy_num; i++) { ret = msm_csiphy_register_entity(&camss->csiphy[i], &camss->v4l2_dev); if (ret < 0) { @@ -1190,7 +1190,7 @@ static int camss_register_entities(struct camss *camss) } } - for (i = 0; i < camss->csid_num; i++) { + for (i = 0; i < camss->res->csid_num; i++) { ret = msm_csid_register_entity(&camss->csid[i], &camss->v4l2_dev); if (ret < 0) { @@ -1209,7 +1209,7 @@ static int camss_register_entities(struct camss *camss) goto err_reg_ispif; } - for (i = 0; i < camss->vfe_num + camss->vfe_lite_num; i++) { + for (i = 0; i < camss->vfe_total_num; i++) { ret = msm_vfe_register_entities(&camss->vfe[i], &camss->v4l2_dev); if (ret < 0) { @@ -1220,8 +1220,8 @@ static int camss_register_entities(struct camss *camss) } } - for (i = 0; i < camss->csiphy_num; i++) { - for (j = 0; j < camss->csid_num; j++) { + for (i = 0; i < camss->res->csiphy_num; i++) { + for (j = 0; j < camss->res->csid_num; j++) { ret = media_create_pad_link( &camss->csiphy[i].subdev.entity, MSM_CSIPHY_PAD_SRC, @@ -1240,7 +1240,7 @@ static int camss_register_entities(struct camss *camss) } if (camss->ispif) { - for (i = 0; i < camss->csid_num; i++) { + for (i = 0; i < camss->res->csid_num; i++) { for (j = 0; j < camss->ispif->line_num; j++) { ret = media_create_pad_link( &camss->csid[i].subdev.entity, @@ -1260,7 +1260,7 @@ static int camss_register_entities(struct camss *camss) } for (i = 0; i < camss->ispif->line_num; i++) - for (k = 0; k < camss->vfe_num; k++) + for (k = 0; k < camss->res->vfe_num; k++) for (j = 0; j < camss->vfe[k].line_num; j++) { struct v4l2_subdev *ispif = &camss->ispif->line[i].subdev; struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev; @@ -1280,8 +1280,8 @@ static int camss_register_entities(struct camss *camss) } } } else { - for (i = 0; i < camss->csid_num; i++) - for (k = 0; k < camss->vfe_num + camss->vfe_lite_num; k++) + for (i = 0; i < camss->res->csid_num; i++) + for (k = 0; k < camss->vfe_total_num; k++) for (j = 0; j < camss->vfe[k].line_num; j++) { struct v4l2_subdev *csid = &camss->csid[i].subdev; struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev; @@ -1305,7 +1305,7 @@ static int camss_register_entities(struct camss *camss) return 0; err_link: - i = camss->vfe_num + camss->vfe_lite_num; + i = camss->vfe_total_num; err_reg_vfe: for (i--; i >= 0; i--) msm_vfe_unregister_entities(&camss->vfe[i]); @@ -1313,12 +1313,12 @@ static int camss_register_entities(struct camss *camss) err_reg_ispif: msm_ispif_unregister_entities(camss->ispif); - i = camss->csid_num; + i = camss->res->csid_num; err_reg_csid: for (i--; i >= 0; i--) msm_csid_unregister_entity(&camss->csid[i]); - i = camss->csiphy_num; + i = camss->res->csiphy_num; err_reg_csiphy: for (i--; i >= 0; i--) msm_csiphy_unregister_entity(&camss->csiphy[i]); @@ -1336,15 +1336,15 @@ static void camss_unregister_entities(struct camss *camss) { unsigned int i; - for (i = 0; i < camss->csiphy_num; i++) + for (i = 0; i < camss->res->csiphy_num; i++) msm_csiphy_unregister_entity(&camss->csiphy[i]); - for (i = 0; i < camss->csid_num; i++) + for (i = 0; i < camss->res->csid_num; i++) msm_csid_unregister_entity(&camss->csid[i]); msm_ispif_unregister_entities(camss->ispif); - for (i = 0; i < camss->vfe_num + camss->vfe_lite_num; i++) + for (i = 0; i < camss->vfe_total_num; i++) msm_vfe_unregister_entities(&camss->vfe[i]); } @@ -1463,7 +1463,7 @@ static int camss_configure_pd(struct camss *camss) } } - if (i > camss->vfe_num) { + if (i > camss->res->vfe_num) { camss->genpd_link[i - 1] = device_link_add(camss->dev, camss->genpd[i - 1], DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); @@ -1506,7 +1506,7 @@ static void camss_genpd_cleanup(struct camss *camss) if (camss->genpd_num == 1) return; - if (camss->genpd_num > camss->vfe_num) + if (camss->genpd_num > camss->res->vfe_num) device_link_del(camss->genpd_link[camss->genpd_num - 1]); for (i = 0; i < camss->genpd_num; i++) @@ -1523,7 +1523,8 @@ static int camss_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct camss *camss; - int num_subdevs, ret; + int num_subdevs; + int ret; camss = devm_kzalloc(dev, sizeof(*camss), GFP_KERNEL); if (!camss) @@ -1535,59 +1536,25 @@ static int camss_probe(struct platform_device *pdev) camss->dev = dev; platform_set_drvdata(pdev, camss); - if (of_device_is_compatible(dev->of_node, "qcom,msm8916-camss")) { - camss->version = CAMSS_8x16; - camss->csiphy_num = 2; - camss->csid_num = 2; - camss->vfe_num = 1; - } else if (of_device_is_compatible(dev->of_node, - "qcom,msm8996-camss")) { - camss->version = CAMSS_8x96; - camss->csiphy_num = 3; - camss->csid_num = 4; - camss->vfe_num = 2; - } else if (of_device_is_compatible(dev->of_node, - "qcom,sdm660-camss")) { - camss->version = CAMSS_660; - camss->csiphy_num = 3; - camss->csid_num = 4; - camss->vfe_num = 2; - } else if (of_device_is_compatible(dev->of_node, - "qcom,sdm845-camss")) { - camss->version = CAMSS_845; - camss->csiphy_num = 4; - camss->csid_num = 3; - camss->vfe_num = 2; - camss->vfe_lite_num = 1; - } else if (of_device_is_compatible(dev->of_node, - "qcom,sm8250-camss")) { - camss->version = CAMSS_8250; - camss->csiphy_num = 6; - camss->csid_num = 4; - camss->vfe_num = 2; - camss->vfe_lite_num = 2; - } else { - return -EINVAL; - } - - camss->csiphy = devm_kcalloc(dev, camss->csiphy_num, + camss->csiphy = devm_kcalloc(dev, camss->res->csiphy_num, sizeof(*camss->csiphy), GFP_KERNEL); if (!camss->csiphy) return -ENOMEM; - camss->csid = devm_kcalloc(dev, camss->csid_num, sizeof(*camss->csid), + camss->csid = devm_kcalloc(dev, camss->res->csid_num, sizeof(*camss->csid), GFP_KERNEL); if (!camss->csid) return -ENOMEM; - if (camss->version == CAMSS_8x16 || - camss->version == CAMSS_8x96) { + if (camss->res->version == CAMSS_8x16 || + camss->res->version == CAMSS_8x96) { camss->ispif = devm_kcalloc(dev, 1, sizeof(*camss->ispif), GFP_KERNEL); if (!camss->ispif) return -ENOMEM; } - camss->vfe = devm_kcalloc(dev, camss->vfe_num + camss->vfe_lite_num, + camss->vfe_total_num = camss->res->vfe_num + camss->res->vfe_lite_num; + camss->vfe = devm_kcalloc(dev, camss->vfe_total_num, sizeof(*camss->vfe), GFP_KERNEL); if (!camss->vfe) return -ENOMEM; @@ -1706,38 +1673,60 @@ static void camss_remove(struct platform_device *pdev) } static const struct camss_resources msm8916_resources = { + .version = CAMSS_8x16, .csiphy_res = csiphy_res_8x16, .csid_res = csid_res_8x16, .ispif_res = &ispif_res_8x16, .vfe_res = vfe_res_8x16, + .csiphy_num = ARRAY_SIZE(csiphy_res_8x16), + .csid_num = ARRAY_SIZE(csid_res_8x16), + .vfe_num = ARRAY_SIZE(vfe_res_8x16), }; static const struct camss_resources msm8996_resources = { + .version = CAMSS_8x96, .csiphy_res = csiphy_res_8x96, .csid_res = csid_res_8x96, .ispif_res = &ispif_res_8x96, .vfe_res = vfe_res_8x96, + .csiphy_num = ARRAY_SIZE(csiphy_res_8x96), + .csid_num = ARRAY_SIZE(csid_res_8x96), + .vfe_num = ARRAY_SIZE(vfe_res_8x96), }; static const struct camss_resources sdm660_resources = { + .version = CAMSS_660, .csiphy_res = csiphy_res_660, .csid_res = csid_res_660, .ispif_res = &ispif_res_660, .vfe_res = vfe_res_660, + .csiphy_num = ARRAY_SIZE(csiphy_res_660), + .csid_num = ARRAY_SIZE(csid_res_660), + .vfe_num = ARRAY_SIZE(vfe_res_660), }; static const struct camss_resources sdm845_resources = { + .version = CAMSS_845, .csiphy_res = csiphy_res_845, .csid_res = csid_res_845, .vfe_res = vfe_res_845, + .csiphy_num = ARRAY_SIZE(csiphy_res_845), + .csid_num = ARRAY_SIZE(csid_res_845), + .vfe_num = 2, + .vfe_lite_num = 1, }; static const struct camss_resources sm8250_resources = { + .version = CAMSS_8250, .csiphy_res = csiphy_res_8250, .csid_res = csid_res_8250, .vfe_res = vfe_res_8250, .icc_res = icc_res_sm8250, .icc_path_num = ARRAY_SIZE(icc_res_sm8250), + .csiphy_num = ARRAY_SIZE(csiphy_res_8250), + .csid_num = ARRAY_SIZE(csid_res_8250), + .vfe_num = 2, + .vfe_lite_num = 2, }; static const struct of_device_id camss_dt_match[] = { diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index 8b2e4adb923ef..3b6562b515d46 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -80,27 +80,27 @@ enum icc_count { }; struct camss_resources { + enum camss_version version; const struct camss_subdev_resources *csiphy_res; const struct camss_subdev_resources *csid_res; const struct camss_subdev_resources *ispif_res; const struct camss_subdev_resources *vfe_res; const struct resources_icc *icc_res; const unsigned int icc_path_num; + const unsigned int csiphy_num; + const unsigned int csid_num; + const unsigned int vfe_num; + const unsigned int vfe_lite_num; }; struct camss { - enum camss_version version; struct v4l2_device v4l2_dev; struct v4l2_async_notifier notifier; struct media_device media_dev; struct device *dev; - int csiphy_num; struct csiphy_device *csiphy; - int csid_num; struct csid_device *csid; struct ispif_device *ispif; - int vfe_num; - int vfe_lite_num; struct vfe_device *vfe; atomic_t ref_count; int genpd_num; @@ -108,6 +108,7 @@ struct camss { struct device_link **genpd_link; struct icc_path *icc_path[ICC_SM8250_COUNT]; const struct camss_resources *res; + unsigned int vfe_total_num; }; struct camss_camera_interface { -- GitLab From 91719b27926a2e382dba8cb161cb244aebddad71 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Mon, 25 Sep 2023 16:46:56 +0100 Subject: [PATCH 0430/1451] media: qcom: camss: Pass line_num from compat resources line_num indicates the number of RDI - raw data interface channels which are associated with a given IFE/VFE - image/video front end. On several SoCs the RDI number is not static for each VFE - for example on sm8250 VFE Lite has four RDIs where regular VFE has three. Assigning line_num statically in the subdev_init() phase initialises each VFE to the lower number, meaning in practical terms that we are lobbing off one RDI on some VFEs. Interrupt handling uses static for (i = RDI0; i < RDI2; i++) {} in some of our VFE blocks but this can't work for situations where we have a mixture of VFE @ 3 RDI and VFE-lite @ 4 RDI blocks. First step to remediate is to pass line_num from a compat string controlled data-structure and do so on a per-VFE basis. Later patches will assign the correct number of RDI blocks per VFE. Signed-off-by: Bryan O'Donoghue Reviewed-by: Konrad Dybcio Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- .../media/platform/qcom/camss/camss-vfe-170.c | 2 -- .../media/platform/qcom/camss/camss-vfe-4-1.c | 2 -- .../media/platform/qcom/camss/camss-vfe-4-7.c | 2 -- .../media/platform/qcom/camss/camss-vfe-4-8.c | 2 -- .../media/platform/qcom/camss/camss-vfe-480.c | 1 - drivers/media/platform/qcom/camss/camss-vfe.c | 5 +++ drivers/media/platform/qcom/camss/camss.c | 36 ++++++++++++------- drivers/media/platform/qcom/camss/camss.h | 1 + 8 files changed, 30 insertions(+), 21 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c index 82d2392022dd1..2ba7160b3bd1e 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-170.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c @@ -753,8 +753,6 @@ static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) { vfe->isr_ops = vfe_isr_ops_170; vfe->video_ops = vfe_video_ops_170; - - vfe->line_num = VFE_LINE_NUM_GEN2; } const struct vfe_hw_ops vfe_ops_170 = { diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c index bc309f326f519..2911e4126e7ad 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c @@ -992,8 +992,6 @@ static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) vfe->isr_ops = vfe_isr_ops_gen1; vfe->ops_gen1 = &vfe_ops_gen1_4_1; vfe->video_ops = vfe_video_ops_gen1; - - vfe->line_num = VFE_LINE_NUM_GEN1; } const struct vfe_hw_ops vfe_ops_4_1 = { diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c index 8acd76c9746ba..b65ed0fef595e 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c @@ -1188,8 +1188,6 @@ static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) vfe->isr_ops = vfe_isr_ops_gen1; vfe->ops_gen1 = &vfe_ops_gen1_4_7; vfe->video_ops = vfe_video_ops_gen1; - - vfe->line_num = VFE_LINE_NUM_GEN1; } const struct vfe_hw_ops vfe_ops_4_7 = { diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c index 3a0167ecf873a..7b3805177f037 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c @@ -1173,8 +1173,6 @@ static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) vfe->isr_ops = vfe_isr_ops_gen1; vfe->ops_gen1 = &vfe_ops_gen1_4_8; vfe->video_ops = vfe_video_ops_gen1; - - vfe->line_num = VFE_LINE_NUM_GEN1; } const struct vfe_hw_ops vfe_ops_4_8 = { diff --git a/drivers/media/platform/qcom/camss/camss-vfe-480.c b/drivers/media/platform/qcom/camss/camss-vfe-480.c index 074fa4e38163e..43a2964121f22 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-480.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-480.c @@ -569,7 +569,6 @@ static const struct camss_video_ops vfe_video_ops_480 = { static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) { vfe->video_ops = vfe_video_ops_480; - vfe->line_num = MAX_VFE_OUTPUT_LINES; } const struct vfe_hw_ops vfe_ops_480 = { diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 94ee7c7039eb3..f381c82f1f877 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -1305,6 +1305,11 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, default: return -EINVAL; } + + if (!res->line_num) + return -EINVAL; + + vfe->line_num = res->line_num; vfe->ops->subdev_init(dev, vfe); /* Memory */ diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index d1152a7db9cd2..54886a2a449b0 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -123,7 +123,8 @@ static const struct camss_subdev_resources vfe_res_8x16[] = { { 0 }, { 0 } }, .reg = { "vfe0" }, - .interrupt = { "vfe0" } + .interrupt = { "vfe0" }, + .line_num = VFE_LINE_NUM_GEN1, } }; @@ -263,7 +264,8 @@ static const struct camss_subdev_resources vfe_res_8x96[] = { { 0 }, { 0 } }, .reg = { "vfe0" }, - .interrupt = { "vfe0" } + .interrupt = { "vfe0" }, + .line_num = VFE_LINE_NUM_GEN1, }, /* VFE1 */ @@ -281,7 +283,8 @@ static const struct camss_subdev_resources vfe_res_8x96[] = { { 0 }, { 0 } }, .reg = { "vfe1" }, - .interrupt = { "vfe1" } + .interrupt = { "vfe1" }, + .line_num = VFE_LINE_NUM_GEN1, } }; @@ -442,7 +445,8 @@ static const struct camss_subdev_resources vfe_res_660[] = { { 0 }, { 0 } }, .reg = { "vfe0" }, - .interrupt = { "vfe0" } + .interrupt = { "vfe0" }, + .line_num = VFE_LINE_NUM_GEN1, }, /* VFE1 */ @@ -463,7 +467,8 @@ static const struct camss_subdev_resources vfe_res_660[] = { { 0 }, { 0 } }, .reg = { "vfe1" }, - .interrupt = { "vfe1" } + .interrupt = { "vfe1" }, + .line_num = VFE_LINE_NUM_GEN1, } }; @@ -621,7 +626,8 @@ static const struct camss_subdev_resources vfe_res_845[] = { { 19200000, 75000000, 384000000, 538666667 }, { 384000000 } }, .reg = { "vfe0" }, - .interrupt = { "vfe0" } + .interrupt = { "vfe0" }, + .line_num = VFE_LINE_NUM_GEN2, }, /* VFE1 */ @@ -641,7 +647,8 @@ static const struct camss_subdev_resources vfe_res_845[] = { { 19200000, 75000000, 384000000, 538666667 }, { 384000000 } }, .reg = { "vfe1" }, - .interrupt = { "vfe1" } + .interrupt = { "vfe1" }, + .line_num = VFE_LINE_NUM_GEN2, }, /* VFE-lite */ @@ -660,7 +667,8 @@ static const struct camss_subdev_resources vfe_res_845[] = { { 19200000, 75000000, 384000000, 538666667 }, { 384000000 } }, .reg = { "vfe_lite" }, - .interrupt = { "vfe_lite" } + .interrupt = { "vfe_lite" }, + .line_num = VFE_LINE_NUM_GEN2, } }; @@ -787,7 +795,8 @@ static const struct camss_subdev_resources vfe_res_8250[] = { { 0 }, { 0 } }, .reg = { "vfe0" }, - .interrupt = { "vfe0" } + .interrupt = { "vfe0" }, + .line_num = 4, }, /* VFE1 */ { @@ -805,7 +814,8 @@ static const struct camss_subdev_resources vfe_res_8250[] = { { 0 }, { 0 } }, .reg = { "vfe1" }, - .interrupt = { "vfe1" } + .interrupt = { "vfe1" }, + .line_num = 4, }, /* VFE2 (lite) */ { @@ -822,7 +832,8 @@ static const struct camss_subdev_resources vfe_res_8250[] = { { 400000000, 480000000 }, { 0 } }, .reg = { "vfe_lite0" }, - .interrupt = { "vfe_lite0" } + .interrupt = { "vfe_lite0" }, + .line_num = 4, }, /* VFE3 (lite) */ { @@ -839,7 +850,8 @@ static const struct camss_subdev_resources vfe_res_8250[] = { { 400000000, 480000000 }, { 0 } }, .reg = { "vfe_lite1" }, - .interrupt = { "vfe_lite1" } + .interrupt = { "vfe_lite1" }, + .line_num = 4, }, }; diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index 3b6562b515d46..fc02aa84a5dd7 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -48,6 +48,7 @@ struct camss_subdev_resources { u32 clock_rate[CAMSS_RES_MAX][CAMSS_RES_MAX]; char *reg[CAMSS_RES_MAX]; char *interrupt[CAMSS_RES_MAX]; + u8 line_num; }; struct icc_bw_tbl { -- GitLab From c23c7998161595b19ee1162da09609c31b5b4393 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Mon, 25 Sep 2023 16:46:57 +0100 Subject: [PATCH 0431/1451] media: qcom: camss: Pass CAMSS subdev callbacks via resource ops pointer It is possible to pass all of the CAMSS subdevice internal operations pointers from the controlling resources structure with an additional pointer added to the resources structure. This allows for the removal of most of the probe-time control structures. Signed-off-by: Bryan O'Donoghue Signed-off-by: Hans Verkuil --- .../media/platform/qcom/camss/camss-csid.c | 12 +- .../media/platform/qcom/camss/camss-csiphy.c | 4 +- drivers/media/platform/qcom/camss/camss-vfe.c | 20 +-- drivers/media/platform/qcom/camss/camss.c | 117 ++++++++++++------ drivers/media/platform/qcom/camss/camss.h | 1 + 5 files changed, 86 insertions(+), 68 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index 14abb7a7ceb47..99f651e2021cb 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -575,18 +575,8 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, csid->camss = camss; csid->id = id; + csid->ops = res->ops; - if (camss->res->version == CAMSS_8x16) { - csid->ops = &csid_ops_4_1; - } else if (camss->res->version == CAMSS_8x96 || - camss->res->version == CAMSS_660) { - csid->ops = &csid_ops_4_7; - } else if (camss->res->version == CAMSS_845 || - camss->res->version == CAMSS_8250) { - csid->ops = &csid_ops_gen2; - } else { - return -EINVAL; - } csid->ops->subdev_init(csid); /* Memory */ diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index 48e6a101ec9c9..4310a132dcbe2 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -556,19 +556,17 @@ int msm_csiphy_subdev_init(struct camss *camss, csiphy->camss = camss; csiphy->id = id; csiphy->cfg.combo_mode = 0; + csiphy->ops = res->ops; if (camss->res->version == CAMSS_8x16) { - csiphy->ops = &csiphy_ops_2ph_1_0; csiphy->formats = csiphy_formats_8x16; csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x16); } else if (camss->res->version == CAMSS_8x96 || camss->res->version == CAMSS_660) { - csiphy->ops = &csiphy_ops_3ph_1_0; csiphy->formats = csiphy_formats_8x96; csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x96); } else if (camss->res->version == CAMSS_845 || camss->res->version == CAMSS_8250) { - csiphy->ops = &csiphy_ops_3ph_1_0; csiphy->formats = csiphy_formats_sdm845; csiphy->nformats = ARRAY_SIZE(csiphy_formats_sdm845); } else { diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index f381c82f1f877..4d5c32d3dddbf 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -1286,25 +1286,7 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, int i, j; int ret; - switch (camss->res->version) { - case CAMSS_8x16: - vfe->ops = &vfe_ops_4_1; - break; - case CAMSS_8x96: - vfe->ops = &vfe_ops_4_7; - break; - case CAMSS_660: - vfe->ops = &vfe_ops_4_8; - break; - case CAMSS_845: - vfe->ops = &vfe_ops_170; - break; - case CAMSS_8250: - vfe->ops = &vfe_ops_480; - break; - default: - return -EINVAL; - } + vfe->ops = res->ops; if (!res->line_num) return -EINVAL; diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 54886a2a449b0..12131d9ea7ca8 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -42,7 +42,8 @@ static const struct camss_subdev_resources csiphy_res_8x16[] = { { 0 }, { 100000000, 200000000 } }, .reg = { "csiphy0", "csiphy0_clk_mux" }, - .interrupt = { "csiphy0" } + .interrupt = { "csiphy0" }, + .ops = &csiphy_ops_2ph_1_0 }, /* CSIPHY1 */ @@ -54,7 +55,8 @@ static const struct camss_subdev_resources csiphy_res_8x16[] = { { 0 }, { 100000000, 200000000 } }, .reg = { "csiphy1", "csiphy1_clk_mux" }, - .interrupt = { "csiphy1" } + .interrupt = { "csiphy1" }, + .ops = &csiphy_ops_2ph_1_0 } }; @@ -73,7 +75,8 @@ static const struct camss_subdev_resources csid_res_8x16[] = { { 0 }, { 0 } }, .reg = { "csid0" }, - .interrupt = { "csid0" } + .interrupt = { "csid0" }, + .ops = &csid_ops_4_1, }, /* CSID1 */ @@ -90,7 +93,8 @@ static const struct camss_subdev_resources csid_res_8x16[] = { { 0 }, { 0 } }, .reg = { "csid1" }, - .interrupt = { "csid1" } + .interrupt = { "csid1" }, + .ops = &csid_ops_4_1, }, }; @@ -125,6 +129,7 @@ static const struct camss_subdev_resources vfe_res_8x16[] = { .reg = { "vfe0" }, .interrupt = { "vfe0" }, .line_num = VFE_LINE_NUM_GEN1, + .ops = &vfe_ops_4_1 } }; @@ -138,7 +143,8 @@ static const struct camss_subdev_resources csiphy_res_8x96[] = { { 0 }, { 100000000, 200000000, 266666667 } }, .reg = { "csiphy0", "csiphy0_clk_mux" }, - .interrupt = { "csiphy0" } + .interrupt = { "csiphy0" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY1 */ @@ -150,7 +156,8 @@ static const struct camss_subdev_resources csiphy_res_8x96[] = { { 0 }, { 100000000, 200000000, 266666667 } }, .reg = { "csiphy1", "csiphy1_clk_mux" }, - .interrupt = { "csiphy1" } + .interrupt = { "csiphy1" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY2 */ @@ -162,7 +169,8 @@ static const struct camss_subdev_resources csiphy_res_8x96[] = { { 0 }, { 100000000, 200000000, 266666667 } }, .reg = { "csiphy2", "csiphy2_clk_mux" }, - .interrupt = { "csiphy2" } + .interrupt = { "csiphy2" }, + .ops = &csiphy_ops_3ph_1_0 } }; @@ -181,7 +189,8 @@ static const struct camss_subdev_resources csid_res_8x96[] = { { 0 }, { 0 } }, .reg = { "csid0" }, - .interrupt = { "csid0" } + .interrupt = { "csid0" }, + .ops = &csid_ops_4_7, }, /* CSID1 */ @@ -198,7 +207,8 @@ static const struct camss_subdev_resources csid_res_8x96[] = { { 0 }, { 0 } }, .reg = { "csid1" }, - .interrupt = { "csid1" } + .interrupt = { "csid1" }, + .ops = &csid_ops_4_7, }, /* CSID2 */ @@ -215,7 +225,8 @@ static const struct camss_subdev_resources csid_res_8x96[] = { { 0 }, { 0 } }, .reg = { "csid2" }, - .interrupt = { "csid2" } + .interrupt = { "csid2" }, + .ops = &csid_ops_4_7, }, /* CSID3 */ @@ -232,7 +243,8 @@ static const struct camss_subdev_resources csid_res_8x96[] = { { 0 }, { 0 } }, .reg = { "csid3" }, - .interrupt = { "csid3" } + .interrupt = { "csid3" }, + .ops = &csid_ops_4_7, } }; @@ -266,6 +278,7 @@ static const struct camss_subdev_resources vfe_res_8x96[] = { .reg = { "vfe0" }, .interrupt = { "vfe0" }, .line_num = VFE_LINE_NUM_GEN1, + .ops = &vfe_ops_4_7 }, /* VFE1 */ @@ -285,6 +298,7 @@ static const struct camss_subdev_resources vfe_res_8x96[] = { .reg = { "vfe1" }, .interrupt = { "vfe1" }, .line_num = VFE_LINE_NUM_GEN1, + .ops = &vfe_ops_4_7 } }; @@ -300,7 +314,8 @@ static const struct camss_subdev_resources csiphy_res_660[] = { { 100000000, 200000000, 269333333 }, { 0 } }, .reg = { "csiphy0", "csiphy0_clk_mux" }, - .interrupt = { "csiphy0" } + .interrupt = { "csiphy0" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY1 */ @@ -314,7 +329,8 @@ static const struct camss_subdev_resources csiphy_res_660[] = { { 100000000, 200000000, 269333333 }, { 0 } }, .reg = { "csiphy1", "csiphy1_clk_mux" }, - .interrupt = { "csiphy1" } + .interrupt = { "csiphy1" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY2 */ @@ -328,7 +344,8 @@ static const struct camss_subdev_resources csiphy_res_660[] = { { 100000000, 200000000, 269333333 }, { 0 } }, .reg = { "csiphy2", "csiphy2_clk_mux" }, - .interrupt = { "csiphy2" } + .interrupt = { "csiphy2" }, + .ops = &csiphy_ops_3ph_1_0 } }; @@ -350,7 +367,8 @@ static const struct camss_subdev_resources csid_res_660[] = { { 0 }, { 0 } }, .reg = { "csid0" }, - .interrupt = { "csid0" } + .interrupt = { "csid0" }, + .ops = &csid_ops_4_7, }, /* CSID1 */ @@ -370,7 +388,8 @@ static const struct camss_subdev_resources csid_res_660[] = { { 0 }, { 0 } }, .reg = { "csid1" }, - .interrupt = { "csid1" } + .interrupt = { "csid1" }, + .ops = &csid_ops_4_7, }, /* CSID2 */ @@ -390,7 +409,8 @@ static const struct camss_subdev_resources csid_res_660[] = { { 0 }, { 0 } }, .reg = { "csid2" }, - .interrupt = { "csid2" } + .interrupt = { "csid2" }, + .ops = &csid_ops_4_7, }, /* CSID3 */ @@ -410,7 +430,8 @@ static const struct camss_subdev_resources csid_res_660[] = { { 0 }, { 0 } }, .reg = { "csid3" }, - .interrupt = { "csid3" } + .interrupt = { "csid3" }, + .ops = &csid_ops_4_7, } }; @@ -447,6 +468,7 @@ static const struct camss_subdev_resources vfe_res_660[] = { .reg = { "vfe0" }, .interrupt = { "vfe0" }, .line_num = VFE_LINE_NUM_GEN1, + .ops = &vfe_ops_4_8 }, /* VFE1 */ @@ -469,6 +491,7 @@ static const struct camss_subdev_resources vfe_res_660[] = { .reg = { "vfe1" }, .interrupt = { "vfe1" }, .line_num = VFE_LINE_NUM_GEN1, + .ops = &vfe_ops_4_8 } }; @@ -488,7 +511,8 @@ static const struct camss_subdev_resources csiphy_res_845[] = { { 0 }, { 19200000, 240000000, 269333333 } }, .reg = { "csiphy0" }, - .interrupt = { "csiphy0" } + .interrupt = { "csiphy0" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY1 */ @@ -506,7 +530,8 @@ static const struct camss_subdev_resources csiphy_res_845[] = { { 0 }, { 19200000, 240000000, 269333333 } }, .reg = { "csiphy1" }, - .interrupt = { "csiphy1" } + .interrupt = { "csiphy1" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY2 */ @@ -524,7 +549,8 @@ static const struct camss_subdev_resources csiphy_res_845[] = { { 0 }, { 19200000, 240000000, 269333333 } }, .reg = { "csiphy2" }, - .interrupt = { "csiphy2" } + .interrupt = { "csiphy2" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY3 */ @@ -542,7 +568,8 @@ static const struct camss_subdev_resources csiphy_res_845[] = { { 0 }, { 19200000, 240000000, 269333333 } }, .reg = { "csiphy3" }, - .interrupt = { "csiphy3" } + .interrupt = { "csiphy3" }, + .ops = &csiphy_ops_3ph_1_0 } }; @@ -564,7 +591,8 @@ static const struct camss_subdev_resources csid_res_845[] = { { 19200000, 75000000, 384000000, 538666667 }, { 384000000 } }, .reg = { "csid0" }, - .interrupt = { "csid0" } + .interrupt = { "csid0" }, + .ops = &csid_ops_gen2 }, /* CSID1 */ @@ -584,7 +612,8 @@ static const struct camss_subdev_resources csid_res_845[] = { { 19200000, 75000000, 384000000, 538666667 }, { 384000000 } }, .reg = { "csid1" }, - .interrupt = { "csid1" } + .interrupt = { "csid1" }, + .ops = &csid_ops_gen2 }, /* CSID2 */ @@ -604,7 +633,8 @@ static const struct camss_subdev_resources csid_res_845[] = { { 19200000, 75000000, 384000000, 538666667 }, { 384000000 } }, .reg = { "csid2" }, - .interrupt = { "csid2" } + .interrupt = { "csid2" }, + .ops = &csid_ops_gen2 } }; @@ -628,6 +658,7 @@ static const struct camss_subdev_resources vfe_res_845[] = { .reg = { "vfe0" }, .interrupt = { "vfe0" }, .line_num = VFE_LINE_NUM_GEN2, + .ops = &vfe_ops_170 }, /* VFE1 */ @@ -649,6 +680,7 @@ static const struct camss_subdev_resources vfe_res_845[] = { .reg = { "vfe1" }, .interrupt = { "vfe1" }, .line_num = VFE_LINE_NUM_GEN2, + .ops = &vfe_ops_170 }, /* VFE-lite */ @@ -669,6 +701,7 @@ static const struct camss_subdev_resources vfe_res_845[] = { .reg = { "vfe_lite" }, .interrupt = { "vfe_lite" }, .line_num = VFE_LINE_NUM_GEN2, + .ops = &vfe_ops_170 } }; @@ -680,7 +713,8 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { .clock_rate = { { 400000000 }, { 300000000 } }, .reg = { "csiphy0" }, - .interrupt = { "csiphy0" } + .interrupt = { "csiphy0" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY1 */ { @@ -689,7 +723,8 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { .clock_rate = { { 400000000 }, { 300000000 } }, .reg = { "csiphy1" }, - .interrupt = { "csiphy1" } + .interrupt = { "csiphy1" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY2 */ { @@ -698,7 +733,8 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { .clock_rate = { { 400000000 }, { 300000000 } }, .reg = { "csiphy2" }, - .interrupt = { "csiphy2" } + .interrupt = { "csiphy2" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY3 */ { @@ -707,7 +743,8 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { .clock_rate = { { 400000000 }, { 300000000 } }, .reg = { "csiphy3" }, - .interrupt = { "csiphy3" } + .interrupt = { "csiphy3" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY4 */ { @@ -716,7 +753,8 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { .clock_rate = { { 400000000 }, { 300000000 } }, .reg = { "csiphy4" }, - .interrupt = { "csiphy4" } + .interrupt = { "csiphy4" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY5 */ { @@ -725,7 +763,8 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { .clock_rate = { { 400000000 }, { 300000000 } }, .reg = { "csiphy5" }, - .interrupt = { "csiphy5" } + .interrupt = { "csiphy5" }, + .ops = &csiphy_ops_3ph_1_0 } }; @@ -740,7 +779,8 @@ static const struct camss_subdev_resources csid_res_8250[] = { { 100000000, 200000000, 300000000, 400000000 }, { 0 } }, .reg = { "csid0" }, - .interrupt = { "csid0" } + .interrupt = { "csid0" }, + .ops = &csid_ops_gen2 }, /* CSID1 */ { @@ -752,7 +792,8 @@ static const struct camss_subdev_resources csid_res_8250[] = { { 100000000, 200000000, 300000000, 400000000 }, { 0 } }, .reg = { "csid1" }, - .interrupt = { "csid1" } + .interrupt = { "csid1" }, + .ops = &csid_ops_gen2 }, /* CSID2 */ { @@ -763,7 +804,8 @@ static const struct camss_subdev_resources csid_res_8250[] = { { 400000000, 480000000 }, { 0 } }, .reg = { "csid2" }, - .interrupt = { "csid2" } + .interrupt = { "csid2" }, + .ops = &csid_ops_gen2 }, /* CSID3 */ { @@ -774,7 +816,8 @@ static const struct camss_subdev_resources csid_res_8250[] = { { 400000000, 480000000 }, { 0 } }, .reg = { "csid3" }, - .interrupt = { "csid3" } + .interrupt = { "csid3" }, + .ops = &csid_ops_gen2 } }; @@ -797,6 +840,7 @@ static const struct camss_subdev_resources vfe_res_8250[] = { .reg = { "vfe0" }, .interrupt = { "vfe0" }, .line_num = 4, + .ops = &vfe_ops_480 }, /* VFE1 */ { @@ -816,6 +860,7 @@ static const struct camss_subdev_resources vfe_res_8250[] = { .reg = { "vfe1" }, .interrupt = { "vfe1" }, .line_num = 4, + .ops = &vfe_ops_480 }, /* VFE2 (lite) */ { @@ -834,6 +879,7 @@ static const struct camss_subdev_resources vfe_res_8250[] = { .reg = { "vfe_lite0" }, .interrupt = { "vfe_lite0" }, .line_num = 4, + .ops = &vfe_ops_480 }, /* VFE3 (lite) */ { @@ -852,6 +898,7 @@ static const struct camss_subdev_resources vfe_res_8250[] = { .reg = { "vfe_lite1" }, .interrupt = { "vfe_lite1" }, .line_num = 4, + .ops = &vfe_ops_480 }, }; diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index fc02aa84a5dd7..8acad7321c09d 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -49,6 +49,7 @@ struct camss_subdev_resources { char *reg[CAMSS_RES_MAX]; char *interrupt[CAMSS_RES_MAX]; u8 line_num; + const void *ops; }; struct icc_bw_tbl { -- GitLab From 7c1340e4c2964d1839c0f9c2e0a4397ab4278b84 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Mon, 25 Sep 2023 16:46:58 +0100 Subject: [PATCH 0432/1451] media: qcom: camss: Assign the correct number of RDIs per VFE Each Video Front End - VFE - has a variable number of Raw Data Interfaces - RDIs associated with it. The CAMSS code started from a naive implementation where a fixed define was used as a control in a for(){} loop iterating through RDIs. That model scales badly. An attempt was made with VFE_LINE_NUM_GEN2 and VFE_LINE_NUM_GEN1 to differentiate between SoCs but, the problem with that is "gen1" and "gen2" have no meaning in the silicon. There is no fixed constraint in the silicon between VFE and RDI, it is entirely up to the SoC designers how many VFEs are populated and how many RDIs to associate with each VFE. As an example sdm845 has VFE version 175 and sm8250 VFE version 480. sdm845 has 2 VFEs with 4 RDIs and 1 VFE Lite with 4 RDIs. sm8250 has 2 VFEs with 3 RDIs and 2 VFE Lite with 4 RDIs. Clearly then we need a more granular model to capture the necessary data. The defines have gone away to be replaced with per-SoC data but, we haven't populated the parameter data with the real values. Let's call those values out now msm8916: 1 x VFE 3 x RDI per VFE (not 4) msm8996: 2 x VFE 3 x RDI per VFE (not 4) sdm660: 2 x VFE 3 x RDI per VFE (not 4) sdm845: 2 x VFE 4 x RDI per VFE (not 3) 1 x VFE Lite 4 x RDI per VFE Lite (not 3) sm8250: 2 x VFE 3 x RDI per VFE (not 4) 2 x VFE Lite 4 x RDI per VFE Lite This more complex and correct mapping was not possible prior to passing values via driver data. Now that we have that change in place we can correctly map VFEs to RDIs for each VFE. Signed-off-by: Bryan O'Donoghue Acked-by: Konrad Dybcio Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss-vfe.h | 2 -- drivers/media/platform/qcom/camss/camss.c | 20 +++++++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index b4bae9f65c68f..4783afa73a365 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -52,9 +52,7 @@ enum vfe_line_id { VFE_LINE_RDI0 = 0, VFE_LINE_RDI1 = 1, VFE_LINE_RDI2 = 2, - VFE_LINE_NUM_GEN2 = 3, VFE_LINE_PIX = 3, - VFE_LINE_NUM_GEN1 = 4, VFE_LINE_NUM_MAX = 4 }; diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 12131d9ea7ca8..8e78dd8d5961e 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -128,7 +128,7 @@ static const struct camss_subdev_resources vfe_res_8x16[] = { { 0 } }, .reg = { "vfe0" }, .interrupt = { "vfe0" }, - .line_num = VFE_LINE_NUM_GEN1, + .line_num = 3, .ops = &vfe_ops_4_1 } }; @@ -277,7 +277,7 @@ static const struct camss_subdev_resources vfe_res_8x96[] = { { 0 } }, .reg = { "vfe0" }, .interrupt = { "vfe0" }, - .line_num = VFE_LINE_NUM_GEN1, + .line_num = 3, .ops = &vfe_ops_4_7 }, @@ -297,7 +297,7 @@ static const struct camss_subdev_resources vfe_res_8x96[] = { { 0 } }, .reg = { "vfe1" }, .interrupt = { "vfe1" }, - .line_num = VFE_LINE_NUM_GEN1, + .line_num = 3, .ops = &vfe_ops_4_7 } }; @@ -467,7 +467,7 @@ static const struct camss_subdev_resources vfe_res_660[] = { { 0 } }, .reg = { "vfe0" }, .interrupt = { "vfe0" }, - .line_num = VFE_LINE_NUM_GEN1, + .line_num = 3, .ops = &vfe_ops_4_8 }, @@ -490,7 +490,7 @@ static const struct camss_subdev_resources vfe_res_660[] = { { 0 } }, .reg = { "vfe1" }, .interrupt = { "vfe1" }, - .line_num = VFE_LINE_NUM_GEN1, + .line_num = 3, .ops = &vfe_ops_4_8 } }; @@ -657,7 +657,7 @@ static const struct camss_subdev_resources vfe_res_845[] = { { 384000000 } }, .reg = { "vfe0" }, .interrupt = { "vfe0" }, - .line_num = VFE_LINE_NUM_GEN2, + .line_num = 4, .ops = &vfe_ops_170 }, @@ -679,7 +679,7 @@ static const struct camss_subdev_resources vfe_res_845[] = { { 384000000 } }, .reg = { "vfe1" }, .interrupt = { "vfe1" }, - .line_num = VFE_LINE_NUM_GEN2, + .line_num = 4, .ops = &vfe_ops_170 }, @@ -700,7 +700,7 @@ static const struct camss_subdev_resources vfe_res_845[] = { { 384000000 } }, .reg = { "vfe_lite" }, .interrupt = { "vfe_lite" }, - .line_num = VFE_LINE_NUM_GEN2, + .line_num = 4, .ops = &vfe_ops_170 } }; @@ -839,7 +839,7 @@ static const struct camss_subdev_resources vfe_res_8250[] = { { 0 } }, .reg = { "vfe0" }, .interrupt = { "vfe0" }, - .line_num = 4, + .line_num = 3, .ops = &vfe_ops_480 }, /* VFE1 */ @@ -859,7 +859,7 @@ static const struct camss_subdev_resources vfe_res_8250[] = { { 0 } }, .reg = { "vfe1" }, .interrupt = { "vfe1" }, - .line_num = 4, + .line_num = 3, .ops = &vfe_ops_480 }, /* VFE2 (lite) */ -- GitLab From b2c2715e5aaf959d8f86a8aceccd537ebbdb19f6 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Mon, 25 Sep 2023 16:46:59 +0100 Subject: [PATCH 0433/1451] media: qcom: camss: Remove special case for VFE get/put From sdm845 onwards we need to ensure the VFE is powered on prior to switching on the CSID. Currently the code tests for sdm845, sm8250 and then does get/set. This is not extensible and it turns out is not necessary either since vfe_get and vfe_set reference count. Remove the over-conservative SoC version check. Signed-off-by: Bryan O'Donoghue Suggested-by: Laurent Pinchart Tested-by: Bryan O'Donoghue # rb3 # db410c Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss-csid.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index 99f651e2021cb..95873f988f7e2 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -159,15 +159,17 @@ static int csid_set_power(struct v4l2_subdev *sd, int on) struct camss *camss = csid->camss; struct device *dev = camss->dev; struct vfe_device *vfe = &camss->vfe[csid->id]; - u32 version = camss->res->version; int ret = 0; if (on) { - if (version == CAMSS_8250 || version == CAMSS_845) { - ret = vfe_get(vfe); - if (ret < 0) - return ret; - } + /* + * From SDM845 onwards, the VFE needs to be powered on before + * switching on the CSID. Do so unconditionally, as there is no + * drawback in following the same powering order on older SoCs. + */ + ret = vfe_get(vfe); + if (ret < 0) + return ret; ret = pm_runtime_resume_and_get(dev); if (ret < 0) @@ -217,8 +219,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on) regulator_bulk_disable(csid->num_supplies, csid->supplies); pm_runtime_put_sync(dev); - if (version == CAMSS_8250 || version == CAMSS_845) - vfe_put(vfe); + vfe_put(vfe); } return ret; -- GitLab From 2de3a6546aeee6807b4315107a0131081fd0205e Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Mon, 25 Sep 2023 16:47:00 +0100 Subject: [PATCH 0434/1451] media: qcom: camss: Untangle if/else spaghetti in camss We have a very convoluted if/else legacy here which needs to be rationalised to make it more sustainable. Adding in another Soc or two will make some of these if statements into increasingly large multi-clause behemoths. Introduce switches in the obvious places to despaghetiify. Signed-off-by: Bryan O'Donoghue Acked-by: Konrad Dybcio Signed-off-by: Hans Verkuil --- .../media/platform/qcom/camss/camss-csiphy.c | 16 +++++---- drivers/media/platform/qcom/camss/camss-vfe.c | 33 +++++++++++-------- .../media/platform/qcom/camss/camss-video.c | 17 +++++----- 3 files changed, 37 insertions(+), 29 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index 4310a132dcbe2..18f9a4defb2a4 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -558,19 +558,21 @@ int msm_csiphy_subdev_init(struct camss *camss, csiphy->cfg.combo_mode = 0; csiphy->ops = res->ops; - if (camss->res->version == CAMSS_8x16) { + switch (camss->res->version) { + case CAMSS_8x16: csiphy->formats = csiphy_formats_8x16; csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x16); - } else if (camss->res->version == CAMSS_8x96 || - camss->res->version == CAMSS_660) { + break; + case CAMSS_8x96: + case CAMSS_660: csiphy->formats = csiphy_formats_8x96; csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x96); - } else if (camss->res->version == CAMSS_845 || - camss->res->version == CAMSS_8250) { + break; + case CAMSS_845: + case CAMSS_8250: csiphy->formats = csiphy_formats_sdm845; csiphy->nformats = ARRAY_SIZE(csiphy_formats_sdm845); - } else { - return -EINVAL; + break; } /* Memory */ diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 4d5c32d3dddbf..db8f68819ded9 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -170,7 +170,8 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, { struct vfe_device *vfe = to_vfe(line); - if (vfe->camss->res->version == CAMSS_8x16) + switch (vfe->camss->res->version) { + case CAMSS_8x16: switch (sink_code) { case MEDIA_BUS_FMT_YUYV8_1X16: { @@ -218,10 +219,11 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, return sink_code; } - else if (vfe->camss->res->version == CAMSS_8x96 || - vfe->camss->res->version == CAMSS_660 || - vfe->camss->res->version == CAMSS_845 || - vfe->camss->res->version == CAMSS_8250) + break; + case CAMSS_8x96: + case CAMSS_660: + case CAMSS_845: + case CAMSS_8250: switch (sink_code) { case MEDIA_BUS_FMT_YUYV8_1X16: { @@ -281,8 +283,9 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, return sink_code; } - else - return 0; + break; + } + return 0; } int vfe_reset(struct vfe_device *vfe) @@ -1379,7 +1382,8 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, init_completion(&l->output.sof); init_completion(&l->output.reg_update); - if (camss->res->version == CAMSS_8x16) { + switch (camss->res->version) { + case CAMSS_8x16: if (i == VFE_LINE_PIX) { l->formats = formats_pix_8x16; l->nformats = ARRAY_SIZE(formats_pix_8x16); @@ -1387,8 +1391,9 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, l->formats = formats_rdi_8x16; l->nformats = ARRAY_SIZE(formats_rdi_8x16); } - } else if (camss->res->version == CAMSS_8x96 || - camss->res->version == CAMSS_660) { + break; + case CAMSS_8x96: + case CAMSS_660: if (i == VFE_LINE_PIX) { l->formats = formats_pix_8x96; l->nformats = ARRAY_SIZE(formats_pix_8x96); @@ -1396,12 +1401,12 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, l->formats = formats_rdi_8x96; l->nformats = ARRAY_SIZE(formats_rdi_8x96); } - } else if (camss->res->version == CAMSS_845 || - camss->res->version == CAMSS_8250) { + break; + case CAMSS_845: + case CAMSS_8250: l->formats = formats_rdi_845; l->nformats = ARRAY_SIZE(formats_rdi_845); - } else { - return -EINVAL; + break; } } diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 46a89b5f6c171..a89da5ef47109 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -1006,7 +1006,8 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, mutex_init(&video->lock); - if (video->camss->res->version == CAMSS_8x16) { + switch (video->camss->res->version) { + case CAMSS_8x16: if (is_pix) { video->formats = formats_pix_8x16; video->nformats = ARRAY_SIZE(formats_pix_8x16); @@ -1014,8 +1015,9 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, video->formats = formats_rdi_8x16; video->nformats = ARRAY_SIZE(formats_rdi_8x16); } - } else if (video->camss->res->version == CAMSS_8x96 || - video->camss->res->version == CAMSS_660) { + break; + case CAMSS_8x96: + case CAMSS_660: if (is_pix) { video->formats = formats_pix_8x96; video->nformats = ARRAY_SIZE(formats_pix_8x96); @@ -1023,13 +1025,12 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, video->formats = formats_rdi_8x96; video->nformats = ARRAY_SIZE(formats_rdi_8x96); } - } else if (video->camss->res->version == CAMSS_845 || - video->camss->res->version == CAMSS_8250) { + break; + case CAMSS_845: + case CAMSS_8250: video->formats = formats_rdi_845; video->nformats = ARRAY_SIZE(formats_rdi_845); - } else { - ret = -EINVAL; - goto error_video_register; + break; } ret = msm_video_init_format(video); -- GitLab From bcd2adfef23aee34d74e0b0a299e3268182cf27f Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Mon, 25 Sep 2023 16:47:01 +0100 Subject: [PATCH 0435/1451] media: qcom: camss: Allow clocks vfeN vfe_liteN or vfe_lite The number of Video Front End - VFE or Image Front End - IFE supported with new SoCs can vary both for the full and lite cases. For example sdm845 has one vfe_lite and two vfe interfaces with the vfe clock called simply "vfe_lite" with no integer postfix. sc8280xp has four vfe and four vfe lite blocks. At the moment we declare vfe_lite0 and vfe_lite1 for sm8250 but never set those clocks because we don't match the strings. We need to support the following clock name formats - vfeN - vfe_liteN - vfe_lite with N being any reasonably sized integer. There are two sites in this code which need to do the same thing, constructing and matching strings with the pattern above, so encapsulate the logic in one function. Signed-off-by: Bryan O'Donoghue Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss-vfe.c | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index db8f68819ded9..4db0d0a1c6a51 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -431,6 +431,20 @@ void vfe_isr_reset_ack(struct vfe_device *vfe) complete(&vfe->reset_complete); } +static int vfe_match_clock_names(struct vfe_device *vfe, + struct camss_clock *clock) +{ + char vfe_name[7]; /* vfeXXX\0 */ + char vfe_lite_name[12]; /* vfe_liteXXX\0 */ + + snprintf(vfe_name, sizeof(vfe_name), "vfe%d", vfe->id); + snprintf(vfe_lite_name, sizeof(vfe_lite_name), "vfe_lite%d", vfe->id); + + return (!strcmp(clock->name, vfe_name) || + !strcmp(clock->name, vfe_lite_name) || + !strcmp(clock->name, "vfe_lite")); +} + /* * vfe_set_clock_rates - Calculate and set clock rates on VFE module * @vfe: VFE device @@ -454,9 +468,7 @@ static int vfe_set_clock_rates(struct vfe_device *vfe) for (i = 0; i < vfe->nclocks; i++) { struct camss_clock *clock = &vfe->clock[i]; - if (!strcmp(clock->name, "vfe0") || - !strcmp(clock->name, "vfe1") || - !strcmp(clock->name, "vfe_lite")) { + if (vfe_match_clock_names(vfe, clock)) { u64 min_rate = 0; long rate; @@ -537,9 +549,7 @@ static int vfe_check_clock_rates(struct vfe_device *vfe) for (i = 0; i < vfe->nclocks; i++) { struct camss_clock *clock = &vfe->clock[i]; - if (!strcmp(clock->name, "vfe0") || - !strcmp(clock->name, "vfe1") || - !strcmp(clock->name, "vfe_lite")) { + if (vfe_match_clock_names(vfe, clock)) { u64 min_rate = 0; unsigned long rate; -- GitLab From 0727615fb975f69c23a9e71cd0a982be67bfe159 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Mon, 25 Sep 2023 16:47:02 +0100 Subject: [PATCH 0436/1451] media: qcom: camss: Functionally decompose CSIPHY clock lookups The csiphyX_timer and csiX_phy values need not be hard-coded. We can functionally decompose the string matching inside of a loop. Static string values are brittle, difficult to extend and not required anyway since the camss->res->csiphy_num value informs us of the number of CSIPHYs and hence the set of potential clocks for a given CSIPHY. In simple terms if we have five CSIPHYs we can have no more and no less than five csiphy_timer clocks. Similarly csi_phy core clocks have a 1:1 relationship with the PHY they clock. Signed-off-by: Bryan O'Donoghue Signed-off-by: Hans Verkuil --- .../media/platform/qcom/camss/camss-csiphy.c | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index 18f9a4defb2a4..20bb361e9ad05 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -536,6 +536,15 @@ static int csiphy_init_formats(struct v4l2_subdev *sd, return csiphy_set_format(sd, fh ? fh->state : NULL, &format); } +static bool csiphy_match_clock_name(const char *clock_name, const char *format, + int index) +{ + char name[16]; /* csiphyXXX_timer\0 */ + + snprintf(name, sizeof(name), format, index); + return !strcmp(clock_name, name); +} + /* * msm_csiphy_subdev_init - Initialize CSIPHY device structure and resources * @csiphy: CSIPHY device @@ -550,7 +559,7 @@ int msm_csiphy_subdev_init(struct camss *camss, { struct device *dev = camss->dev; struct platform_device *pdev = to_platform_device(dev); - int i, j; + int i, j, k; int ret; csiphy->camss = camss; @@ -656,19 +665,19 @@ int msm_csiphy_subdev_init(struct camss *camss, for (j = 0; j < clock->nfreqs; j++) clock->freq[j] = res->clock_rate[i][j]; - if (!strcmp(clock->name, "csiphy0_timer") || - !strcmp(clock->name, "csiphy1_timer") || - !strcmp(clock->name, "csiphy2_timer") || - !strcmp(clock->name, "csiphy3_timer") || - !strcmp(clock->name, "csiphy4_timer") || - !strcmp(clock->name, "csiphy5_timer")) - csiphy->rate_set[i] = true; - - if (camss->res->version == CAMSS_660 && - (!strcmp(clock->name, "csi0_phy") || - !strcmp(clock->name, "csi1_phy") || - !strcmp(clock->name, "csi2_phy"))) - csiphy->rate_set[i] = true; + for (k = 0; k < camss->res->csiphy_num; k++) { + csiphy->rate_set[i] = csiphy_match_clock_name(clock->name, + "csiphy%d_timer", k); + if (csiphy->rate_set[i]) + break; + + if (camss->res->version == CAMSS_660) { + csiphy->rate_set[i] = csiphy_match_clock_name(clock->name, + "csi%d_phy", k); + if (csiphy->rate_set[i]) + break; + } + } } return 0; -- GitLab From 35a62432af1ee9041fde0e1afe1d019ca82516cc Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Mon, 25 Sep 2023 16:47:03 +0100 Subject: [PATCH 0437/1451] media: qcom: camss: Fix support for setting CSIPHY clock name csiphyX Several of our upstream and soon-to-be upstream SoC CAMSS dtsi declare csiphyX as opposed to the older clock name csiX_phy. Right now the CAMSS code will fail to set the csiphyX clock even if we have declared it in our list of clocks. For sdm845 and sm8250 we appear to "get away" with this error, however on sc8280xp we don't. The right approach here is to set the clock when it is declared. If a SoC doesn't require or a SoC driver implementer doesn't think we need, then the clock ought to simply be omitted from the clock list. Include csiphyX in the set of permissible strings which will subsequently lead to the csiphyX clock being set during csiphy_set_clock_rates() phase. sdm845 and sm8250 will work with the code as-is so I've omitted this from a suggested Fixes list. Signed-off-by: Bryan O'Donoghue Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss-csiphy.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index 20bb361e9ad05..edd573606a6ae 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -677,6 +677,10 @@ int msm_csiphy_subdev_init(struct camss *camss, if (csiphy->rate_set[i]) break; } + + csiphy->rate_set[i] = csiphy_match_clock_name(clock->name, "csiphy%d", k); + if (csiphy->rate_set[i]) + break; } } -- GitLab From 2ce0bd411b826dca852f7452d267c5f924c5f3f7 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Mon, 25 Sep 2023 16:47:04 +0100 Subject: [PATCH 0438/1451] media: qcom: camss: Support RDI3 for VFE 17x Some VFEs have four RDIs apiece. Right now the ISR code has a hard-coded value which tops-out at RDI2 meaning only three RDIs can be utilised in practice. Extend out the various routines in camss-vfe-17x.c to support the higher RDI count. Signed-off-by: Bryan O'Donoghue Acked-by: Konrad Dybcio Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss-vfe-170.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c index 2ba7160b3bd1e..a5aa799501861 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-170.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c @@ -209,7 +209,8 @@ static void vfe_global_reset(struct vfe_device *vfe) GLOBAL_RESET_CMD_IDLE_CGC | GLOBAL_RESET_CMD_RDI0 | GLOBAL_RESET_CMD_RDI1 | - GLOBAL_RESET_CMD_RDI2; + GLOBAL_RESET_CMD_RDI2 | + GLOBAL_RESET_CMD_RDI3; writel_relaxed(BIT(31), vfe->base + VFE_IRQ_MASK_0); @@ -343,7 +344,7 @@ static void vfe_violation_read(struct vfe_device *vfe) static irqreturn_t vfe_isr(int irq, void *dev) { struct vfe_device *vfe = dev; - u32 status0, status1, vfe_bus_status[3]; + u32 status0, status1, vfe_bus_status[VFE_LINE_NUM_MAX]; int i, wm; status0 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_0); @@ -352,7 +353,7 @@ static irqreturn_t vfe_isr(int irq, void *dev) writel_relaxed(status0, vfe->base + VFE_IRQ_CLEAR_0); writel_relaxed(status1, vfe->base + VFE_IRQ_CLEAR_1); - for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++) { + for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) { vfe_bus_status[i] = readl_relaxed(vfe->base + VFE_BUS_IRQ_STATUS(i)); writel_relaxed(vfe_bus_status[i], vfe->base + VFE_BUS_IRQ_CLEAR(i)); } @@ -366,11 +367,11 @@ static irqreturn_t vfe_isr(int irq, void *dev) if (status0 & STATUS_0_RESET_ACK) vfe->isr_ops.reset_ack(vfe); - for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++) + for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) if (status0 & STATUS_0_RDI_REG_UPDATE(i)) vfe->isr_ops.reg_update(vfe, i); - for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++) + for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) if (status0 & STATUS_1_RDI_SOF(i)) vfe->isr_ops.sof(vfe, i); -- GitLab From 90cc4555730bfd0fc6af5c8a5a81d80bfce4cff7 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Mon, 25 Sep 2023 16:47:05 +0100 Subject: [PATCH 0439/1451] media: qcom: camss: Move vfe_disable into a common routine where applicable We can move vfe_disable() into a common routine in the core VFE file provided we make wm_stop() a VFE specific callback. The callback is required to capture the case where VFE 17x currently isn't VC enabled where as VFE 480 is. Suggested-by: Laurent Pinchart Signed-off-by: Bryan O'Donoghue Signed-off-by: Hans Verkuil --- .../media/platform/qcom/camss/camss-vfe-170.c | 40 +------------------ .../media/platform/qcom/camss/camss-vfe-480.c | 40 +------------------ drivers/media/platform/qcom/camss/camss-vfe.c | 39 ++++++++++++++++++ drivers/media/platform/qcom/camss/camss-vfe.h | 9 +++++ 4 files changed, 50 insertions(+), 78 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c index a5aa799501861..0b211fed12760 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-170.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c @@ -494,22 +494,6 @@ static int vfe_enable_output(struct vfe_line *line) return 0; } -static void vfe_disable_output(struct vfe_line *line) -{ - struct vfe_device *vfe = to_vfe(line); - struct vfe_output *output = &line->output; - unsigned long flags; - unsigned int i; - - spin_lock_irqsave(&vfe->output_lock, flags); - for (i = 0; i < output->wm_num; i++) - vfe_wm_stop(vfe, output->wm_idx[i]); - output->gen2.active_num = 0; - spin_unlock_irqrestore(&vfe->output_lock, flags); - - vfe_reset(vfe); -} - /* * vfe_enable - Enable streaming on VFE line * @line: VFE line @@ -555,29 +539,6 @@ static int vfe_enable(struct vfe_line *line) return ret; } -/* - * vfe_disable - Disable streaming on VFE line - * @line: VFE line - * - * Return 0 on success or a negative error code otherwise - */ -static int vfe_disable(struct vfe_line *line) -{ - struct vfe_device *vfe = to_vfe(line); - - vfe_disable_output(line); - - vfe_put_output(line); - - mutex_lock(&vfe->stream_lock); - - vfe->stream_count--; - - mutex_unlock(&vfe->stream_lock); - - return 0; -} - /* * vfe_isr_sof - Process start of frame interrupt * @vfe: VFE Device @@ -770,4 +731,5 @@ const struct vfe_hw_ops vfe_ops_170 = { .vfe_enable = vfe_enable, .vfe_halt = vfe_halt, .violation_read = vfe_violation_read, + .vfe_wm_stop = vfe_wm_stop, }; diff --git a/drivers/media/platform/qcom/camss/camss-vfe-480.c b/drivers/media/platform/qcom/camss/camss-vfe-480.c index 43a2964121f22..f2368b77fc6d6 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-480.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-480.c @@ -327,22 +327,6 @@ static int vfe_enable_output(struct vfe_line *line) return 0; } -static void vfe_disable_output(struct vfe_line *line) -{ - struct vfe_device *vfe = to_vfe(line); - struct vfe_output *output = &line->output; - unsigned long flags; - unsigned int i; - - spin_lock_irqsave(&vfe->output_lock, flags); - for (i = 0; i < output->wm_num; i++) - vfe_wm_stop(vfe, output->wm_idx[i]); - output->gen2.active_num = 0; - spin_unlock_irqrestore(&vfe->output_lock, flags); - - vfe_reset(vfe); -} - /* * vfe_enable - Enable streaming on VFE line * @line: VFE line @@ -390,29 +374,6 @@ static int vfe_enable(struct vfe_line *line) return ret; } -/* - * vfe_disable - Disable streaming on VFE line - * @line: VFE line - * - * Return 0 on success or a negative error code otherwise - */ -static int vfe_disable(struct vfe_line *line) -{ - struct vfe_device *vfe = to_vfe(line); - - vfe_disable_output(line); - - vfe_put_output(line); - - mutex_lock(&vfe->stream_lock); - - vfe->stream_count--; - - mutex_unlock(&vfe->stream_lock); - - return 0; -} - /* * vfe_isr_reg_update - Process reg update interrupt * @vfe: VFE Device @@ -581,4 +542,5 @@ const struct vfe_hw_ops vfe_ops_480 = { .vfe_disable = vfe_disable, .vfe_enable = vfe_enable, .vfe_halt = vfe_halt, + .vfe_wm_stop = vfe_wm_stop, }; diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 4db0d0a1c6a51..b3d5af7f09690 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -410,6 +410,45 @@ int vfe_put_output(struct vfe_line *line) return 0; } +static int vfe_disable_output(struct vfe_line *line) +{ + struct vfe_device *vfe = to_vfe(line); + struct vfe_output *output = &line->output; + unsigned long flags; + unsigned int i; + + spin_lock_irqsave(&vfe->output_lock, flags); + for (i = 0; i < output->wm_num; i++) + vfe->ops->vfe_wm_stop(vfe, output->wm_idx[i]); + output->gen2.active_num = 0; + spin_unlock_irqrestore(&vfe->output_lock, flags); + + return vfe_reset(vfe); +} + +/* + * vfe_disable - Disable streaming on VFE line + * @line: VFE line + * + * Return 0 on success or a negative error code otherwise + */ +int vfe_disable(struct vfe_line *line) +{ + struct vfe_device *vfe = to_vfe(line); + + vfe_disable_output(line); + + vfe_put_output(line); + + mutex_lock(&vfe->stream_lock); + + vfe->stream_count--; + + mutex_unlock(&vfe->stream_lock); + + return 0; +} + /** * vfe_isr_comp_done() - Process composite image done interrupt * @vfe: VFE Device diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index 4783afa73a365..09baded0dcdd6 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -114,6 +114,7 @@ struct vfe_hw_ops { int (*vfe_enable)(struct vfe_line *line); int (*vfe_halt)(struct vfe_device *vfe); void (*violation_read)(struct vfe_device *vfe); + void (*vfe_wm_stop)(struct vfe_device *vfe, u8 wm); }; struct vfe_isr_ops { @@ -192,6 +193,14 @@ int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id); */ int vfe_reset(struct vfe_device *vfe); +/* + * vfe_disable - Disable streaming on VFE line + * @line: VFE line + * + * Return 0 on success or a negative error code otherwise + */ +int vfe_disable(struct vfe_line *line); + extern const struct vfe_hw_ops vfe_ops_4_1; extern const struct vfe_hw_ops vfe_ops_4_7; extern const struct vfe_hw_ops vfe_ops_4_8; -- GitLab From 5c07f30bed52ed85673b634f77467e404645785d Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Mon, 25 Sep 2023 16:47:06 +0100 Subject: [PATCH 0440/1451] media: qcom: camss: Propagate vfe_reset error up the callstack A previous patch I had removed the returns from vfe_disable() since we didn't trap any meaningful errors. Konrad pointed out vfe_reset() could return an error, which is true. Trap the vfe_reset() error code and throw it up the callstack. Suggested-by: Konrad Dybcio Signed-off-by: Bryan O'Donoghue Signed-off-by: Hans Verkuil --- drivers/media/platform/qcom/camss/camss-vfe.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index b3d5af7f09690..4839e2cedfe58 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -435,8 +435,11 @@ static int vfe_disable_output(struct vfe_line *line) int vfe_disable(struct vfe_line *line) { struct vfe_device *vfe = to_vfe(line); + int ret; - vfe_disable_output(line); + ret = vfe_disable_output(line); + if (ret) + goto error; vfe_put_output(line); @@ -446,7 +449,8 @@ int vfe_disable(struct vfe_line *line) mutex_unlock(&vfe->stream_lock); - return 0; +error: + return ret; } /** -- GitLab From f910d3ba78a2677c23508f225eb047d89eb4b2b6 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Thu, 28 Sep 2023 01:58:25 +0100 Subject: [PATCH 0441/1451] media: qcom: camss: Comment CSID dt_id field Digging into the documentation we find that the DT_ID bitfield is used to map the six bit DT to a two bit ID code. This value is concatenated to the VC bitfield to create a CID value. DT_ID is the two least significant bits of CID and VC the most significant bits. Originally we set dt_id = vc * 4 in and then subsequently set dt_id = vc. commit 3c4ed72a16bc ("media: camss: sm8250: Virtual channels for CSID") silently fixed the multiplication by four which would give a better value for the generated CID without mentioning what was being done or why. Next up I haplessly changed the value back to "dt_id = vc * 4" since there didn't appear to be any logic behind it. Hans asked what the change was for and I honestly couldn't remember the provenance of it, so I dug in. Link: https://lore.kernel.org/linux-arm-msm/edd4bf9b-0e1b-883c-1a4d-50f4102c3924@xs4all.nl/ Add a comment so the next hapless programmer doesn't make this same mistake. Signed-off-by: Bryan O'Donoghue Signed-off-by: Hans Verkuil --- .../media/platform/qcom/camss/camss-csid-gen2.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen2.c b/drivers/media/platform/qcom/camss/camss-csid-gen2.c index 6ba2b10326444..05ff5fa8095a8 100644 --- a/drivers/media/platform/qcom/camss/camss-csid-gen2.c +++ b/drivers/media/platform/qcom/camss/camss-csid-gen2.c @@ -352,7 +352,19 @@ static void __csid_configure_stream(struct csid_device *csid, u8 enable, u8 vc) phy_sel = csid->phy.csiphy_id; if (enable) { - u8 dt_id = vc; + /* + * DT_ID is a two bit bitfield that is concatenated with + * the four least significant bits of the five bit VC + * bitfield to generate an internal CID value. + * + * CSID_RDI_CFG0(vc) + * DT_ID : 28:27 + * VC : 26:22 + * DT : 21:16 + * + * CID : VC 3:0 << 2 | DT_ID 1:0 + */ + u8 dt_id = vc & 0x03; if (tg->enabled) { /* configure one DT, infinite frames */ -- GitLab From 6496617b2b06d7004a5cbd53d48f19567d6b018c Mon Sep 17 00:00:00 2001 From: Ming Qian Date: Thu, 7 Sep 2023 09:51:00 +0800 Subject: [PATCH 0442/1451] media: amphion: handle firmware debug message decoder firmware may notify host some debug message, it can help analyze the state of the firmware in case of error Fixes: 9f599f351e86 ("media: amphion: add vpu core driver") Signed-off-by: Ming Qian Reviewed-by: Nicolas Dufresne Signed-off-by: Hans Verkuil --- drivers/media/platform/amphion/vpu_defs.h | 1 + drivers/media/platform/amphion/vpu_helpers.c | 1 + drivers/media/platform/amphion/vpu_malone.c | 1 + drivers/media/platform/amphion/vpu_msgs.c | 31 ++++++++++++++++---- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/amphion/vpu_defs.h b/drivers/media/platform/amphion/vpu_defs.h index 667637eedb5d4..7320852668d64 100644 --- a/drivers/media/platform/amphion/vpu_defs.h +++ b/drivers/media/platform/amphion/vpu_defs.h @@ -71,6 +71,7 @@ enum { VPU_MSG_ID_TIMESTAMP_INFO, VPU_MSG_ID_FIRMWARE_XCPT, VPU_MSG_ID_PIC_SKIPPED, + VPU_MSG_ID_DBG_MSG, }; enum VPU_ENC_MEMORY_RESOURSE { diff --git a/drivers/media/platform/amphion/vpu_helpers.c b/drivers/media/platform/amphion/vpu_helpers.c index af3b336e5dc32..d12310af9ebce 100644 --- a/drivers/media/platform/amphion/vpu_helpers.c +++ b/drivers/media/platform/amphion/vpu_helpers.c @@ -489,6 +489,7 @@ const char *vpu_id_name(u32 id) case VPU_MSG_ID_UNSUPPORTED: return "unsupported"; case VPU_MSG_ID_FIRMWARE_XCPT: return "exception"; case VPU_MSG_ID_PIC_SKIPPED: return "skipped"; + case VPU_MSG_ID_DBG_MSG: return "debug msg"; } return ""; } diff --git a/drivers/media/platform/amphion/vpu_malone.c b/drivers/media/platform/amphion/vpu_malone.c index f771661980c01..d3425de7bccd3 100644 --- a/drivers/media/platform/amphion/vpu_malone.c +++ b/drivers/media/platform/amphion/vpu_malone.c @@ -745,6 +745,7 @@ static struct vpu_pair malone_msgs[] = { {VPU_MSG_ID_UNSUPPORTED, VID_API_EVENT_UNSUPPORTED_STREAM}, {VPU_MSG_ID_FIRMWARE_XCPT, VID_API_EVENT_FIRMWARE_XCPT}, {VPU_MSG_ID_PIC_SKIPPED, VID_API_EVENT_PIC_SKIPPED}, + {VPU_MSG_ID_DBG_MSG, VID_API_EVENT_DBG_MSG_DEC}, }; static void vpu_malone_pack_fs_alloc(struct vpu_rpc_event *pkt, diff --git a/drivers/media/platform/amphion/vpu_msgs.c b/drivers/media/platform/amphion/vpu_msgs.c index d0ead051f7d18..b74a407a19f22 100644 --- a/drivers/media/platform/amphion/vpu_msgs.c +++ b/drivers/media/platform/amphion/vpu_msgs.c @@ -23,6 +23,7 @@ struct vpu_msg_handler { u32 id; void (*done)(struct vpu_inst *inst, struct vpu_rpc_event *pkt); + u32 is_str; }; static void vpu_session_handle_start_done(struct vpu_inst *inst, struct vpu_rpc_event *pkt) @@ -154,7 +155,7 @@ static void vpu_session_handle_error(struct vpu_inst *inst, struct vpu_rpc_event { char *str = (char *)pkt->data; - if (strlen(str)) + if (*str) dev_err(inst->dev, "instance %d firmware error : %s\n", inst->id, str); else dev_err(inst->dev, "instance %d is unsupported stream\n", inst->id); @@ -180,6 +181,21 @@ static void vpu_session_handle_pic_skipped(struct vpu_inst *inst, struct vpu_rpc vpu_inst_unlock(inst); } +static void vpu_session_handle_dbg_msg(struct vpu_inst *inst, struct vpu_rpc_event *pkt) +{ + char *str = (char *)pkt->data; + + if (*str) + dev_info(inst->dev, "instance %d firmware dbg msg : %s\n", inst->id, str); +} + +static void vpu_terminate_string_msg(struct vpu_rpc_event *pkt) +{ + if (pkt->hdr.num == ARRAY_SIZE(pkt->data)) + pkt->hdr.num--; + pkt->data[pkt->hdr.num] = 0; +} + static struct vpu_msg_handler handlers[] = { {VPU_MSG_ID_START_DONE, vpu_session_handle_start_done}, {VPU_MSG_ID_STOP_DONE, vpu_session_handle_stop_done}, @@ -193,9 +209,10 @@ static struct vpu_msg_handler handlers[] = { {VPU_MSG_ID_PIC_DECODED, vpu_session_handle_pic_decoded}, {VPU_MSG_ID_DEC_DONE, vpu_session_handle_pic_done}, {VPU_MSG_ID_PIC_EOS, vpu_session_handle_eos}, - {VPU_MSG_ID_UNSUPPORTED, vpu_session_handle_error}, - {VPU_MSG_ID_FIRMWARE_XCPT, vpu_session_handle_firmware_xcpt}, + {VPU_MSG_ID_UNSUPPORTED, vpu_session_handle_error, true}, + {VPU_MSG_ID_FIRMWARE_XCPT, vpu_session_handle_firmware_xcpt, true}, {VPU_MSG_ID_PIC_SKIPPED, vpu_session_handle_pic_skipped}, + {VPU_MSG_ID_DBG_MSG, vpu_session_handle_dbg_msg, true}, }; static int vpu_session_handle_msg(struct vpu_inst *inst, struct vpu_rpc_event *msg) @@ -219,8 +236,12 @@ static int vpu_session_handle_msg(struct vpu_inst *inst, struct vpu_rpc_event *m } } - if (handler && handler->done) - handler->done(inst, msg); + if (handler) { + if (handler->is_str) + vpu_terminate_string_msg(msg); + if (handler->done) + handler->done(inst, msg); + } vpu_response_cmd(inst, msg_id, 1); -- GitLab From cab0c4e94c49641563fa929af0cd6ffb62154acd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 7 Sep 2023 10:54:31 +0200 Subject: [PATCH 0443/1451] media: Documentation: dv-timings.rst: explain basic approach Explain how the DV Timings API and the V4L2_EVENT_SOURCE_CHANGE event work together to handle video source changes. Signed-off-by: Hans Verkuil --- .../userspace-api/media/v4l/dv-timings.rst | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Documentation/userspace-api/media/v4l/dv-timings.rst b/Documentation/userspace-api/media/v4l/dv-timings.rst index e17f056b129f0..4b19bcb4bd80d 100644 --- a/Documentation/userspace-api/media/v4l/dv-timings.rst +++ b/Documentation/userspace-api/media/v4l/dv-timings.rst @@ -33,6 +33,27 @@ current DV timings they use the the DV timings as seen by the video receiver applications use the :ref:`VIDIOC_QUERY_DV_TIMINGS` ioctl. +When the hardware detects a video source change (e.g. the video +signal appears or disappears, or the video resolution changes), then +it will issue a `V4L2_EVENT_SOURCE_CHANGE` event. Use the +:ref:`ioctl VIDIOC_SUBSCRIBE_EVENT ` and the +:ref:`VIDIOC_DQEVENT` to check if this event was reported. + +If the video signal changed, then the application has to stop +streaming, free all buffers, and call the :ref:`VIDIOC_QUERY_DV_TIMINGS` +to obtain the new video timings, and if they are valid, it can set +those by calling the :ref:`ioctl VIDIOC_S_DV_TIMINGS `. +This will also update the format, so use the :ref:`ioctl VIDIOC_G_FMT ` +to obtain the new format. Now the application can allocate new buffers +and start streaming again. + +The :ref:`VIDIOC_QUERY_DV_TIMINGS` will just report what the +hardware detects, it will never change the configuration. If the +currently set timings and the actually detected timings differ, then +typically this will mean that you will not be able to capture any +video. The correct approach is to rely on the `V4L2_EVENT_SOURCE_CHANGE` +event so you know when something changed. + Applications can make use of the :ref:`input-capabilities` and :ref:`output-capabilities` flags to determine whether the digital video ioctls can be used with the given input or output. -- GitLab From c3cad51c66bbed05e126b796592ff91033bd9e4e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 7 Sep 2023 11:55:21 +0200 Subject: [PATCH 0444/1451] media: platform: mtk-mdp3: add missing of_node_put for_each_child_of_node performs an of_node_get on each iteration, so a break out of the loop requires an of_node_put. This was done using the Coccinelle semantic patch iterators/for_each_child.cocci Signed-off-by: Julia Lawall Signed-off-by: Hans Verkuil --- drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c index 667933ea15f44..575c8d52acd19 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c @@ -1137,6 +1137,7 @@ int mdp_comp_config(struct mdp_dev *mdp) comp = mdp_comp_create(mdp, node, id); if (IS_ERR(comp)) { ret = PTR_ERR(comp); + of_node_put(node); goto err_init_comps; } -- GitLab From 0aeccc63f3bc4cfd49dc4893da1409402ee6b295 Mon Sep 17 00:00:00 2001 From: Fei Shao Date: Fri, 8 Sep 2023 21:28:04 +0800 Subject: [PATCH 0445/1451] media: mtk-jpegenc: Fix bug in JPEG encode quality selection The driver uses the upper-bound approach to decide the target JPEG encode quality, but there's a logic bug that if the desired quality is higher than what the driver can support, the driver falls back to using the worst quality. Fix the bug by assuming using the best quality in the beginning, and with trivial refactor to avoid long lines. Fixes: 45f13a57d813 ("media: platform: Add jpeg enc feature") Signed-off-by: Fei Shao Reviewed-by: Chen-Yu Tsai Signed-off-by: Hans Verkuil --- drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c index 2bbc48c7402ca..f8fa3b841ccfb 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c @@ -127,6 +127,7 @@ void mtk_jpeg_set_enc_params(struct mtk_jpeg_ctx *ctx, void __iomem *base) u32 img_stride; u32 mem_stride; u32 i, enc_quality; + u32 nr_enc_quality = ARRAY_SIZE(mtk_jpeg_enc_quality); value = width << 16 | height; writel(value, base + JPEG_ENC_IMG_SIZE); @@ -157,8 +158,8 @@ void mtk_jpeg_set_enc_params(struct mtk_jpeg_ctx *ctx, void __iomem *base) writel(img_stride, base + JPEG_ENC_IMG_STRIDE); writel(mem_stride, base + JPEG_ENC_STRIDE); - enc_quality = mtk_jpeg_enc_quality[0].hardware_value; - for (i = 0; i < ARRAY_SIZE(mtk_jpeg_enc_quality); i++) { + enc_quality = mtk_jpeg_enc_quality[nr_enc_quality - 1].hardware_value; + for (i = 0; i < nr_enc_quality; i++) { if (ctx->enc_quality <= mtk_jpeg_enc_quality[i].quality_param) { enc_quality = mtk_jpeg_enc_quality[i].hardware_value; break; -- GitLab From a142f7bb8908902120480ce3dbd799a9c63c84a2 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sun, 10 Sep 2023 16:21:59 +0100 Subject: [PATCH 0446/1451] media: i2c: adv7180: Extend match support for OF tables The driver has an OF match table, still, it uses an ID lookup table for retrieving match data. Currently, the driver is working on the assumption that an I2C device registered via OF will always match a legacy I2C device ID. The correct approach is to have an OF device ID table using i2c_get_match_data() if the devices are registered via OF/ID. Unify the OF/ID table by using struct adv7180_chip_info as match data for both these tables and replace the ID lookup table for the match data by i2c_get_match_data(). While at it, remove the trailing comma in the terminator entry for the OF table making code robust against (theoretical) misrebases or other similar things where the new entry goes _after_ the termination without the compiler noticing. Signed-off-by: Biju Das Reviewed-by: Jacopo Mondi Signed-off-by: Hans Verkuil --- drivers/media/i2c/adv7180.c | 60 ++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 99ba925e8ec8e..fc4f29e74e05c 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -1395,7 +1395,6 @@ static int init_device(struct adv7180_state *state) static int adv7180_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct device_node *np = client->dev.of_node; struct adv7180_state *state; struct v4l2_subdev *sd; @@ -1411,7 +1410,7 @@ static int adv7180_probe(struct i2c_client *client) state->client = client; state->field = V4L2_FIELD_ALTERNATE; - state->chip_info = (struct adv7180_chip_info *)id->driver_data; + state->chip_info = i2c_get_match_data(client); state->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown", GPIOD_OUT_HIGH); @@ -1536,22 +1535,6 @@ static void adv7180_remove(struct i2c_client *client) mutex_destroy(&state->mutex); } -static const struct i2c_device_id adv7180_id[] = { - { "adv7180", (kernel_ulong_t)&adv7180_info }, - { "adv7180cp", (kernel_ulong_t)&adv7180_info }, - { "adv7180st", (kernel_ulong_t)&adv7180_info }, - { "adv7182", (kernel_ulong_t)&adv7182_info }, - { "adv7280", (kernel_ulong_t)&adv7280_info }, - { "adv7280-m", (kernel_ulong_t)&adv7280_m_info }, - { "adv7281", (kernel_ulong_t)&adv7281_info }, - { "adv7281-m", (kernel_ulong_t)&adv7281_m_info }, - { "adv7281-ma", (kernel_ulong_t)&adv7281_ma_info }, - { "adv7282", (kernel_ulong_t)&adv7282_info }, - { "adv7282-m", (kernel_ulong_t)&adv7282_m_info }, - {}, -}; -MODULE_DEVICE_TABLE(i2c, adv7180_id); - #ifdef CONFIG_PM_SLEEP static int adv7180_suspend(struct device *dev) { @@ -1585,22 +1568,37 @@ static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume); #define ADV7180_PM_OPS NULL #endif +static const struct i2c_device_id adv7180_id[] = { + { "adv7180", (kernel_ulong_t)&adv7180_info }, + { "adv7180cp", (kernel_ulong_t)&adv7180_info }, + { "adv7180st", (kernel_ulong_t)&adv7180_info }, + { "adv7182", (kernel_ulong_t)&adv7182_info }, + { "adv7280", (kernel_ulong_t)&adv7280_info }, + { "adv7280-m", (kernel_ulong_t)&adv7280_m_info }, + { "adv7281", (kernel_ulong_t)&adv7281_info }, + { "adv7281-m", (kernel_ulong_t)&adv7281_m_info }, + { "adv7281-ma", (kernel_ulong_t)&adv7281_ma_info }, + { "adv7282", (kernel_ulong_t)&adv7282_info }, + { "adv7282-m", (kernel_ulong_t)&adv7282_m_info }, + {} +}; +MODULE_DEVICE_TABLE(i2c, adv7180_id); + #ifdef CONFIG_OF static const struct of_device_id adv7180_of_id[] = { - { .compatible = "adi,adv7180", }, - { .compatible = "adi,adv7180cp", }, - { .compatible = "adi,adv7180st", }, - { .compatible = "adi,adv7182", }, - { .compatible = "adi,adv7280", }, - { .compatible = "adi,adv7280-m", }, - { .compatible = "adi,adv7281", }, - { .compatible = "adi,adv7281-m", }, - { .compatible = "adi,adv7281-ma", }, - { .compatible = "adi,adv7282", }, - { .compatible = "adi,adv7282-m", }, - { }, + { .compatible = "adi,adv7180", &adv7180_info }, + { .compatible = "adi,adv7180cp", &adv7180_info }, + { .compatible = "adi,adv7180st", &adv7180_info }, + { .compatible = "adi,adv7182", &adv7182_info }, + { .compatible = "adi,adv7280", &adv7280_info }, + { .compatible = "adi,adv7280-m", &adv7280_m_info }, + { .compatible = "adi,adv7281", &adv7281_info }, + { .compatible = "adi,adv7281-m", &adv7281_m_info }, + { .compatible = "adi,adv7281-ma", &adv7281_ma_info }, + { .compatible = "adi,adv7282", &adv7282_info }, + { .compatible = "adi,adv7282-m", &adv7282_m_info }, + {} }; - MODULE_DEVICE_TABLE(of, adv7180_of_id); #endif -- GitLab From 56a8c694c524d146a2d0b06aaff84544be9f5fa9 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sun, 10 Sep 2023 16:22:00 +0100 Subject: [PATCH 0447/1451] media: i2c: adv7180: Drop CONFIG_OF ifdeffery Drop of_match_ptr() from adv7180_driver and get rid of ugly CONFIG_OF if check. This slightly increases the size of adv7180_driver on non-OF system and shouldn't be an issue. Add mod_devicetable.h include. It also allows, in case if needed, to enumerate this device via ACPI with PRP0001 magic. Signed-off-by: Biju Das Reviewed-by: Jacopo Mondi Signed-off-by: Hans Verkuil --- drivers/media/i2c/adv7180.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index fc4f29e74e05c..54134473186bf 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -5,6 +5,7 @@ * Copyright (C) 2013 Cogent Embedded, Inc. * Copyright (C) 2013 Renesas Solutions Corp. */ +#include #include #include #include @@ -1584,7 +1585,6 @@ static const struct i2c_device_id adv7180_id[] = { }; MODULE_DEVICE_TABLE(i2c, adv7180_id); -#ifdef CONFIG_OF static const struct of_device_id adv7180_of_id[] = { { .compatible = "adi,adv7180", &adv7180_info }, { .compatible = "adi,adv7180cp", &adv7180_info }, @@ -1600,13 +1600,12 @@ static const struct of_device_id adv7180_of_id[] = { {} }; MODULE_DEVICE_TABLE(of, adv7180_of_id); -#endif static struct i2c_driver adv7180_driver = { .driver = { .name = KBUILD_MODNAME, .pm = ADV7180_PM_OPS, - .of_match_table = of_match_ptr(adv7180_of_id), + .of_match_table = adv7180_of_id, }, .probe = adv7180_probe, .remove = adv7180_remove, -- GitLab From f301fedbeecfdce91cb898d6fa5e62f269801fee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Wed, 13 Sep 2023 15:27:40 +0300 Subject: [PATCH 0448/1451] media: cobalt: Use FIELD_GET() to extract Link Width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use FIELD_GET() to extract PCIe Negotiated and Maximum Link Width fields instead of custom masking and shifting. Signed-off-by: Ilpo Järvinen Reviewed-by: Jonathan Cameron Signed-off-by: Hans Verkuil --- drivers/media/pci/cobalt/cobalt-driver.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index 74edcc76d12f4..6e1a0614e6d06 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.c +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -8,6 +8,7 @@ * All rights reserved. */ +#include #include #include #include @@ -210,17 +211,17 @@ void cobalt_pcie_status_show(struct cobalt *cobalt) pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &stat); cobalt_info("PCIe link capability 0x%08x: %s per lane and %u lanes\n", capa, get_link_speed(capa), - (capa & PCI_EXP_LNKCAP_MLW) >> 4); + FIELD_GET(PCI_EXP_LNKCAP_MLW, capa)); cobalt_info("PCIe link control 0x%04x\n", ctrl); cobalt_info("PCIe link status 0x%04x: %s per lane and %u lanes\n", stat, get_link_speed(stat), - (stat & PCI_EXP_LNKSTA_NLW) >> 4); + FIELD_GET(PCI_EXP_LNKSTA_NLW, stat)); /* Bus */ pcie_capability_read_dword(pci_bus_dev, PCI_EXP_LNKCAP, &capa); cobalt_info("PCIe bus link capability 0x%08x: %s per lane and %u lanes\n", capa, get_link_speed(capa), - (capa & PCI_EXP_LNKCAP_MLW) >> 4); + FIELD_GET(PCI_EXP_LNKCAP_MLW, capa)); /* Slot */ pcie_capability_read_dword(pci_dev, PCI_EXP_SLTCAP, &capa); @@ -239,7 +240,7 @@ static unsigned pcie_link_get_lanes(struct cobalt *cobalt) if (!pci_is_pcie(pci_dev)) return 0; pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &link); - return (link & PCI_EXP_LNKSTA_NLW) >> 4; + return FIELD_GET(PCI_EXP_LNKSTA_NLW, link); } static unsigned pcie_bus_link_get_lanes(struct cobalt *cobalt) @@ -250,7 +251,7 @@ static unsigned pcie_bus_link_get_lanes(struct cobalt *cobalt) if (!pci_is_pcie(pci_dev)) return 0; pcie_capability_read_dword(pci_dev, PCI_EXP_LNKCAP, &link); - return (link & PCI_EXP_LNKCAP_MLW) >> 4; + return FIELD_GET(PCI_EXP_LNKCAP_MLW, link); } static void msi_config_show(struct cobalt *cobalt, struct pci_dev *pci_dev) -- GitLab From 61334819aca018c3416ee6c330a08a49c1524fc3 Mon Sep 17 00:00:00 2001 From: Katya Orlova Date: Fri, 22 Sep 2023 14:55:06 +0300 Subject: [PATCH 0449/1451] media: s3c-camif: Avoid inappropriate kfree() s3c_camif_register_video_node() works with video_device structure stored as a field of camif_vp, so it should not be kfreed. But there is video_device_release() on error path that do it. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: babde1c243b2 ("[media] V4L: Add driver for S3C24XX/S3C64XX SoC series camera interface") Signed-off-by: Katya Orlova Signed-off-by: Hans Verkuil --- drivers/media/platform/samsung/s3c-camif/camif-capture.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/samsung/s3c-camif/camif-capture.c b/drivers/media/platform/samsung/s3c-camif/camif-capture.c index 76634d242b103..0f5b3845d7b94 100644 --- a/drivers/media/platform/samsung/s3c-camif/camif-capture.c +++ b/drivers/media/platform/samsung/s3c-camif/camif-capture.c @@ -1133,12 +1133,12 @@ int s3c_camif_register_video_node(struct camif_dev *camif, int idx) ret = vb2_queue_init(q); if (ret) - goto err_vd_rel; + return ret; vp->pad.flags = MEDIA_PAD_FL_SINK; ret = media_entity_pads_init(&vfd->entity, 1, &vp->pad); if (ret) - goto err_vd_rel; + return ret; video_set_drvdata(vfd, vp); @@ -1171,8 +1171,6 @@ int s3c_camif_register_video_node(struct camif_dev *camif, int idx) v4l2_ctrl_handler_free(&vp->ctrl_handler); err_me_cleanup: media_entity_cleanup(&vfd->entity); -err_vd_rel: - video_device_release(vfd); return ret; } -- GitLab From d425557814ab039012294aa6fd7dc0dd7f3ac4e3 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 22 Sep 2023 10:49:36 -0700 Subject: [PATCH 0450/1451] media: allegro: Annotate struct mcu_msg_push_buffers_internal with __counted_by Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct mcu_msg_push_buffers_internal. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: Michael Tretter Cc: Pengutronix Kernel Team Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Signed-off-by: Hans Verkuil --- drivers/media/platform/allegro-dvt/allegro-mail.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/allegro-dvt/allegro-mail.h b/drivers/media/platform/allegro-dvt/allegro-mail.h index a5686058d7547..c0c9013f1aab3 100644 --- a/drivers/media/platform/allegro-dvt/allegro-mail.h +++ b/drivers/media/platform/allegro-dvt/allegro-mail.h @@ -184,7 +184,7 @@ struct mcu_msg_push_buffers_internal { struct mcu_msg_header header; u32 channel_id; size_t num_buffers; - struct mcu_msg_push_buffers_internal_buffer buffer[]; + struct mcu_msg_push_buffers_internal_buffer buffer[] __counted_by(num_buffers); }; struct mcu_msg_put_stream_buffer { -- GitLab From 54b6b605b9a00f5d93b48734122fa87ae345981e Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 22 Sep 2023 10:49:52 -0700 Subject: [PATCH 0451/1451] media: v4l2-event: Annotate struct v4l2_subscribed_event with __counted_by Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct v4l2_subscribed_event. Additionally, since the element count member must be set before accessing the annotated flexible array member, move its initialization earlier. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: lijian Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Signed-off-by: Hans Verkuil --- drivers/media/v4l2-core/v4l2-event.c | 2 +- include/media/v4l2-event.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-event.c b/drivers/media/v4l2-core/v4l2-event.c index c5ce9f11ad7bc..3898ff7edddbf 100644 --- a/drivers/media/v4l2-core/v4l2-event.c +++ b/drivers/media/v4l2-core/v4l2-event.c @@ -238,6 +238,7 @@ int v4l2_event_subscribe(struct v4l2_fh *fh, sev = kvzalloc(struct_size(sev, events, elems), GFP_KERNEL); if (!sev) return -ENOMEM; + sev->elems = elems; for (i = 0; i < elems; i++) sev->events[i].sev = sev; sev->type = sub->type; @@ -245,7 +246,6 @@ int v4l2_event_subscribe(struct v4l2_fh *fh, sev->flags = sub->flags; sev->fh = fh; sev->ops = ops; - sev->elems = elems; mutex_lock(&fh->subscribe_lock); diff --git a/include/media/v4l2-event.h b/include/media/v4l2-event.h index 4ffa914ade3a1..3a0e2588361cf 100644 --- a/include/media/v4l2-event.h +++ b/include/media/v4l2-event.h @@ -78,7 +78,7 @@ struct v4l2_subscribed_event { unsigned int elems; unsigned int first; unsigned int in_use; - struct v4l2_kevent events[]; + struct v4l2_kevent events[] __counted_by(elems); }; /** -- GitLab From 0b135b89212f6e02ba8b5938973a5d3dcf0e548b Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 23 Sep 2023 17:36:39 +0100 Subject: [PATCH 0452/1451] media: tvp541x: Extend match support for OF tables The driver has an OF match table, still, it uses an ID lookup table for retrieving match data. Currently, the driver is working on the assumption that an I2C device registered via OF will always match a legacy I2C device ID. The correct approach is to have an OF device ID table using i2c_get_match_data() if the devices are registered via OF/ID. Unify the OF/ID table by using tvp514x_reg as match data for both these tables and replace the ID lookup table for the match data by i2c_get_match_data() and simplifly probe(). While at it, remove the trailing comma in the terminator entry for the OF table making code robust against (theoretical) misrebases or other similar things where the new entry goes _after_ the termination without the compiler noticing. Signed-off-by: Biju Das Reviewed-by: Jacopo Mondi Signed-off-by: Hans Verkuil --- drivers/media/i2c/tvp514x.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index aa6d4b67b6d50..4d0ffaa312c59 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -118,7 +118,7 @@ struct tvp514x_decoder { struct media_pad pad; struct v4l2_mbus_framefmt format; - struct tvp514x_reg *int_seq; + const struct tvp514x_reg *int_seq; }; /* TVP514x default register values */ @@ -1024,7 +1024,6 @@ tvp514x_get_pdata(struct i2c_client *client) static int tvp514x_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct tvp514x_platform_data *pdata = tvp514x_get_pdata(client); struct tvp514x_decoder *decoder; struct v4l2_subdev *sd; @@ -1049,7 +1048,7 @@ tvp514x_probe(struct i2c_client *client) memcpy(decoder->tvp514x_regs, tvp514x_reg_list_default, sizeof(tvp514x_reg_list_default)); - decoder->int_seq = (struct tvp514x_reg *)id->driver_data; + decoder->int_seq = i2c_get_match_data(client); /* Copy board specific information here */ decoder->pdata = pdata; @@ -1183,22 +1182,21 @@ static const struct tvp514x_reg tvp514xm_init_reg_seq[] = { * driver_data - Driver data */ static const struct i2c_device_id tvp514x_id[] = { - {"tvp5146", (unsigned long)tvp5146_init_reg_seq}, - {"tvp5146m2", (unsigned long)tvp514xm_init_reg_seq}, - {"tvp5147", (unsigned long)tvp5147_init_reg_seq}, - {"tvp5147m1", (unsigned long)tvp514xm_init_reg_seq}, - {}, + {"tvp5146", (kernel_ulong_t)tvp5146_init_reg_seq }, + {"tvp5146m2", (kernel_ulong_t)tvp514xm_init_reg_seq }, + {"tvp5147", (kernel_ulong_t)tvp5147_init_reg_seq }, + {"tvp5147m1", (kernel_ulong_t)tvp514xm_init_reg_seq }, + { /* sentinel */ } }; - MODULE_DEVICE_TABLE(i2c, tvp514x_id); #if IS_ENABLED(CONFIG_OF) static const struct of_device_id tvp514x_of_match[] = { - { .compatible = "ti,tvp5146", }, - { .compatible = "ti,tvp5146m2", }, - { .compatible = "ti,tvp5147", }, - { .compatible = "ti,tvp5147m1", }, - { /* sentinel */ }, + { .compatible = "ti,tvp5146", .data = tvp5146_init_reg_seq }, + { .compatible = "ti,tvp5146m2", .data = tvp514xm_init_reg_seq }, + { .compatible = "ti,tvp5147", .data = tvp5147_init_reg_seq }, + { .compatible = "ti,tvp5147m1", .data = tvp514xm_init_reg_seq }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, tvp514x_of_match); #endif -- GitLab From 2fa264283d207ab4213e2b88259db1e7ce5d5d1d Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 23 Sep 2023 17:36:40 +0100 Subject: [PATCH 0453/1451] media: tvp541x: Drop CONFIG_OF ifdeffery Drop of_match_ptr() from tvp514x_driver and get rid of ugly CONFIG_OF if check. This slightly increases the size of tvp514x_driver on non-OF system and shouldn't be an issue. Add mod_devicetable.h include. It also allows, in case if needed, to enumerate this device via ACPI with PRP0001 magic. Signed-off-by: Biju Das Reviewed-by: Jacopo Mondi Signed-off-by: Hans Verkuil --- drivers/media/i2c/tvp514x.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 4d0ffaa312c59..569a9437ec864 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -1190,7 +1191,6 @@ static const struct i2c_device_id tvp514x_id[] = { }; MODULE_DEVICE_TABLE(i2c, tvp514x_id); -#if IS_ENABLED(CONFIG_OF) static const struct of_device_id tvp514x_of_match[] = { { .compatible = "ti,tvp5146", .data = tvp5146_init_reg_seq }, { .compatible = "ti,tvp5146m2", .data = tvp514xm_init_reg_seq }, @@ -1199,11 +1199,10 @@ static const struct of_device_id tvp514x_of_match[] = { { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, tvp514x_of_match); -#endif static struct i2c_driver tvp514x_driver = { .driver = { - .of_match_table = of_match_ptr(tvp514x_of_match), + .of_match_table = tvp514x_of_match, .name = TVP514X_MODULE_NAME, }, .probe = tvp514x_probe, -- GitLab From 06a185a861daa80e894419b932c78fa90dd837ac Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 23 Sep 2023 17:36:41 +0100 Subject: [PATCH 0454/1451] media: tvp541x: Sort header files Sort header files alphabetically. Suggested-by: Jacopo Mondi Signed-off-by: Biju Das Signed-off-by: Hans Verkuil --- drivers/media/i2c/tvp514x.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 569a9437ec864..c37f605cb75f6 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -16,24 +16,24 @@ * Prabhakar Lad */ -#include -#include #include -#include +#include #include #include -#include #include #include +#include +#include +#include +#include +#include #include -#include #include -#include -#include #include -#include -#include +#include +#include +#include #include "tvp514x_regs.h" -- GitLab From 3568cb6556695af163e930a75b1ed8f6dfa848ba Mon Sep 17 00:00:00 2001 From: Irui Wang Date: Mon, 25 Sep 2023 12:02:00 +0800 Subject: [PATCH 0455/1451] media: mediatek: vcodec: add encoder power management helper functions Remove PM functions at start/stop streaming, add PM helper functions to get PM before encoding frame start and put PM after encoding frame done. Meanwhile, remove unnecessary clock operations. Signed-off-by: Irui Wang Signed-off-by: Hans Verkuil --- .../mediatek/vcodec/encoder/mtk_vcodec_enc.c | 21 +++---------------- .../vcodec/encoder/mtk_vcodec_enc_pm.c | 18 ++++++++++++++++ .../vcodec/encoder/mtk_vcodec_enc_pm.h | 3 ++- .../mediatek/vcodec/encoder/venc_drv_if.c | 8 ++----- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c index 04948d3eb011a..eb381fa6e7d14 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c @@ -866,7 +866,7 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) { struct mtk_vcodec_enc_ctx *ctx = vb2_get_drv_priv(q); struct venc_enc_param param; - int ret, pm_ret; + int ret; int i; /* Once state turn into MTK_STATE_ABORT, we need stop_streaming @@ -886,18 +886,12 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) return 0; } - ret = pm_runtime_resume_and_get(&ctx->dev->plat_dev->dev); - if (ret < 0) { - mtk_v4l2_venc_err(ctx, "pm_runtime_resume_and_get fail %d", ret); - goto err_start_stream; - } - mtk_venc_set_param(ctx, ¶m); ret = venc_if_set_param(ctx, VENC_SET_PARAM_ENC, ¶m); if (ret) { mtk_v4l2_venc_err(ctx, "venc_if_set_param failed=%d", ret); ctx->state = MTK_STATE_ABORT; - goto err_set_param; + goto err_start_stream; } ctx->param_change = MTK_ENCODE_PARAM_NONE; @@ -910,18 +904,13 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) if (ret) { mtk_v4l2_venc_err(ctx, "venc_if_set_param failed=%d", ret); ctx->state = MTK_STATE_ABORT; - goto err_set_param; + goto err_start_stream; } ctx->state = MTK_STATE_HEADER; } return 0; -err_set_param: - pm_ret = pm_runtime_put(&ctx->dev->plat_dev->dev); - if (pm_ret < 0) - mtk_v4l2_venc_err(ctx, "pm_runtime_put fail %d", pm_ret); - err_start_stream: for (i = 0; i < q->num_buffers; ++i) { struct vb2_buffer *buf = vb2_get_buffer(q, i); @@ -1004,10 +993,6 @@ static void vb2ops_venc_stop_streaming(struct vb2_queue *q) if (ret) mtk_v4l2_venc_err(ctx, "venc_if_deinit failed=%d", ret); - ret = pm_runtime_put(&ctx->dev->plat_dev->dev); - if (ret < 0) - mtk_v4l2_venc_err(ctx, "pm_runtime_put fail %d", ret); - ctx->state = MTK_STATE_FREE; } diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.c index 3fce936e61b9f..a22b7dfc656e1 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.c @@ -58,6 +58,24 @@ int mtk_vcodec_init_enc_clk(struct mtk_vcodec_enc_dev *mtkdev) return 0; } +void mtk_vcodec_enc_pw_on(struct mtk_vcodec_pm *pm) +{ + int ret; + + ret = pm_runtime_resume_and_get(pm->dev); + if (ret) + dev_err(pm->dev, "pm_runtime_resume_and_get fail: %d", ret); +} + +void mtk_vcodec_enc_pw_off(struct mtk_vcodec_pm *pm) +{ + int ret; + + ret = pm_runtime_put(pm->dev); + if (ret && ret != -EAGAIN) + dev_err(pm->dev, "pm_runtime_put fail %d", ret); +} + void mtk_vcodec_enc_clock_on(struct mtk_vcodec_pm *pm) { struct mtk_vcodec_clk *enc_clk = &pm->venc_clk; diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.h b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.h index e50be0575190a..157ea08ba9e36 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.h +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.h @@ -10,7 +10,8 @@ #include "mtk_vcodec_enc_drv.h" int mtk_vcodec_init_enc_clk(struct mtk_vcodec_enc_dev *dev); - +void mtk_vcodec_enc_pw_on(struct mtk_vcodec_pm *pm); +void mtk_vcodec_enc_pw_off(struct mtk_vcodec_pm *pm); void mtk_vcodec_enc_clock_on(struct mtk_vcodec_pm *pm); void mtk_vcodec_enc_clock_off(struct mtk_vcodec_pm *pm); diff --git a/drivers/media/platform/mediatek/vcodec/encoder/venc_drv_if.c b/drivers/media/platform/mediatek/vcodec/encoder/venc_drv_if.c index 1bdaecdd64a79..c402a686f3cb2 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/venc_drv_if.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/venc_drv_if.c @@ -32,9 +32,7 @@ int venc_if_init(struct mtk_vcodec_enc_ctx *ctx, unsigned int fourcc) } mtk_venc_lock(ctx); - mtk_vcodec_enc_clock_on(&ctx->dev->pm); ret = ctx->enc_if->init(ctx); - mtk_vcodec_enc_clock_off(&ctx->dev->pm); mtk_venc_unlock(ctx); return ret; @@ -46,9 +44,7 @@ int venc_if_set_param(struct mtk_vcodec_enc_ctx *ctx, int ret = 0; mtk_venc_lock(ctx); - mtk_vcodec_enc_clock_on(&ctx->dev->pm); ret = ctx->enc_if->set_param(ctx->drv_handle, type, in); - mtk_vcodec_enc_clock_off(&ctx->dev->pm); mtk_venc_unlock(ctx); return ret; @@ -68,10 +64,12 @@ int venc_if_encode(struct mtk_vcodec_enc_ctx *ctx, ctx->dev->curr_ctx = ctx; spin_unlock_irqrestore(&ctx->dev->irqlock, flags); + mtk_vcodec_enc_pw_on(&ctx->dev->pm); mtk_vcodec_enc_clock_on(&ctx->dev->pm); ret = ctx->enc_if->encode(ctx->drv_handle, opt, frm_buf, bs_buf, result); mtk_vcodec_enc_clock_off(&ctx->dev->pm); + mtk_vcodec_enc_pw_off(&ctx->dev->pm); spin_lock_irqsave(&ctx->dev->irqlock, flags); ctx->dev->curr_ctx = NULL; @@ -89,9 +87,7 @@ int venc_if_deinit(struct mtk_vcodec_enc_ctx *ctx) return 0; mtk_venc_lock(ctx); - mtk_vcodec_enc_clock_on(&ctx->dev->pm); ret = ctx->enc_if->deinit(ctx->drv_handle); - mtk_vcodec_enc_clock_off(&ctx->dev->pm); mtk_venc_unlock(ctx); ctx->drv_handle = NULL; -- GitLab From 04d19e65137e3cd4a5004e624c85c762933d115c Mon Sep 17 00:00:00 2001 From: Chengfeng Ye Date: Tue, 26 Sep 2023 10:53:30 +0000 Subject: [PATCH 0456/1451] media: s5p-mfc: Fix potential deadlock on condlock As &dev->condlock is acquired under irq context along the following call chain from s5p_mfc_irq(), other acquisition of the same lock inside process context or softirq context should disable irq avoid double lock. enc_post_frame_start() seems to be one such function that execute under process context or softirq context. enc_post_frame_start() --> clear_work_bit() --> spin_loc(&dev->condlock) --> s5p_mfc_irq() --> s5p_mfc_handle_frame() --> clear_work_bit() --> spin_lock(&dev->condlock) This flaw was found by an experimental static analysis tool I am developing for irq-related deadlock. To prevent the potential deadlock, the patch change clear_work_bit() inside enc_post_frame_start() to clear_work_bit_irqsave(). Signed-off-by: Chengfeng Ye Acked-by: Marek Szyprowski Signed-off-by: Hans Verkuil --- drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c index f62703cebb77c..4b4c129c09e70 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c @@ -1297,7 +1297,7 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) if (ctx->state == MFCINST_FINISHING && ctx->ref_queue_cnt == 0) src_ready = false; if (!src_ready || ctx->dst_queue_cnt == 0) - clear_work_bit(ctx); + clear_work_bit_irqsave(ctx); return 0; } -- GitLab From 5f9fcbf92da901495f2f8b09d2f6df5c2ca83dc5 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 27 Sep 2023 15:39:43 +0300 Subject: [PATCH 0457/1451] media: nuvoton: npcm-video: Fix IS_ERR() vs NULL bug The of_parse_phandle() function returns NULL on error. It never returns error pointers. Update the check accordingly. Fixes: 70721089985c ("media: nuvoton: Add driver for NPCM video capture and encoding engine") Signed-off-by: Dan Carpenter Signed-off-by: Hans Verkuil --- drivers/media/platform/nuvoton/npcm-video.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/nuvoton/npcm-video.c b/drivers/media/platform/nuvoton/npcm-video.c index ac8d73b794d37..b9e6782f59b42 100644 --- a/drivers/media/platform/nuvoton/npcm-video.c +++ b/drivers/media/platform/nuvoton/npcm-video.c @@ -1660,9 +1660,9 @@ static int npcm_video_ece_init(struct npcm_video *video) void __iomem *regs; ece_node = of_parse_phandle(video->dev->of_node, "nuvoton,ece", 0); - if (IS_ERR(ece_node)) { + if (!ece_node) { dev_err(dev, "Failed to get ECE phandle in DTS\n"); - return PTR_ERR(ece_node); + return -ENODEV; } video->ece.enable = of_device_is_available(ece_node); -- GitLab From 76a2c5df6ca8bd8ada45e953b8c72b746f42918d Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Mon, 19 Jun 2023 16:12:01 +0800 Subject: [PATCH 0458/1451] media: vidtv: psi: Add check for kstrdup Add check for the return value of kstrdup() and return the error if it fails in order to avoid NULL pointer dereference. Fixes: 7a7899f6f58e ("media: vidtv: psi: Implement an Event Information Table (EIT)") Fixes: c2f78f0cb294 ("media: vidtv: psi: add a Network Information Table (NIT)") Fixes: f90cf6079bf6 ("media: vidtv: add a bridge driver") Signed-off-by: Jiasheng Jiang Signed-off-by: Hans Verkuil --- drivers/media/test-drivers/vidtv/vidtv_psi.c | 45 +++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/drivers/media/test-drivers/vidtv/vidtv_psi.c b/drivers/media/test-drivers/vidtv/vidtv_psi.c index ce0b7a6e92dc3..2a51c898c11eb 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_psi.c +++ b/drivers/media/test-drivers/vidtv/vidtv_psi.c @@ -301,16 +301,29 @@ struct vidtv_psi_desc_service *vidtv_psi_service_desc_init(struct vidtv_psi_desc desc->service_name_len = service_name_len; - if (service_name && service_name_len) + if (service_name && service_name_len) { desc->service_name = kstrdup(service_name, GFP_KERNEL); + if (!desc->service_name) + goto free_desc; + } desc->provider_name_len = provider_name_len; - if (provider_name && provider_name_len) + if (provider_name && provider_name_len) { desc->provider_name = kstrdup(provider_name, GFP_KERNEL); + if (!desc->provider_name) + goto free_desc_service_name; + } vidtv_psi_desc_chain(head, (struct vidtv_psi_desc *)desc); return desc; + +free_desc_service_name: + if (service_name && service_name_len) + kfree(desc->service_name); +free_desc: + kfree(desc); + return NULL; } struct vidtv_psi_desc_registration @@ -355,8 +368,13 @@ struct vidtv_psi_desc_network_name desc->length = network_name_len; - if (network_name && network_name_len) + if (network_name && network_name_len) { desc->network_name = kstrdup(network_name, GFP_KERNEL); + if (!desc->network_name) { + kfree(desc); + return NULL; + } + } vidtv_psi_desc_chain(head, (struct vidtv_psi_desc *)desc); return desc; @@ -442,15 +460,32 @@ struct vidtv_psi_desc_short_event iso_language_code = "eng"; desc->iso_language_code = kstrdup(iso_language_code, GFP_KERNEL); + if (!desc->iso_language_code) + goto free_desc; - if (event_name && event_name_len) + if (event_name && event_name_len) { desc->event_name = kstrdup(event_name, GFP_KERNEL); + if (!desc->event_name) + goto free_desc_language_code; + } - if (text && text_len) + if (text && text_len) { desc->text = kstrdup(text, GFP_KERNEL); + if (!desc->text) + goto free_desc_event_name; + } vidtv_psi_desc_chain(head, (struct vidtv_psi_desc *)desc); return desc; + +free_desc_event_name: + if (event_name && event_name_len) + kfree(desc->event_name); +free_desc_language_code: + kfree(desc->iso_language_code); +free_desc: + kfree(desc); + return NULL; } struct vidtv_psi_desc *vidtv_psi_desc_clone(struct vidtv_psi_desc *desc) -- GitLab From 1fd6eb12642e0c32692924ff359c07de4b781d78 Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Mon, 19 Jun 2023 16:12:02 +0800 Subject: [PATCH 0459/1451] media: vidtv: mux: Add check and kfree for kstrdup Add check for the return value of kstrdup() and return the error if it fails in order to avoid NULL pointer dereference. Moreover, use kfree() in the later error handling in order to avoid memory leak. Fixes: c2f78f0cb294 ("media: vidtv: psi: add a Network Information Table (NIT)") Signed-off-by: Jiasheng Jiang Signed-off-by: Hans Verkuil --- drivers/media/test-drivers/vidtv/vidtv_mux.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/test-drivers/vidtv/vidtv_mux.c b/drivers/media/test-drivers/vidtv/vidtv_mux.c index b51e6a3b8cbeb..f99878eff7ace 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_mux.c +++ b/drivers/media/test-drivers/vidtv/vidtv_mux.c @@ -504,13 +504,16 @@ struct vidtv_mux *vidtv_mux_init(struct dvb_frontend *fe, m->priv = args->priv; m->network_id = args->network_id; m->network_name = kstrdup(args->network_name, GFP_KERNEL); + if (!m->network_name) + goto free_mux_buf; + m->timing.current_jiffies = get_jiffies_64(); if (args->channels) m->channels = args->channels; else if (vidtv_channels_init(m) < 0) - goto free_mux_buf; + goto free_mux_network_name; /* will alloc data for pmt_sections after initializing pat */ if (vidtv_channel_si_init(m) < 0) @@ -527,6 +530,8 @@ struct vidtv_mux *vidtv_mux_init(struct dvb_frontend *fe, vidtv_channel_si_destroy(m); free_channels: vidtv_channels_destroy(m); +free_mux_network_name: + kfree(m->network_name); free_mux_buf: vfree(m->mux_buf); free_mux: -- GitLab From 85b901e6003b54f1377f63e9444466972c0707a7 Mon Sep 17 00:00:00 2001 From: Ross Zwisler Date: Tue, 29 Aug 2023 14:46:01 -0600 Subject: [PATCH 0460/1451] media: visl: use canonical ftrace path The canonical location for the tracefs filesystem is at /sys/kernel/tracing. But, from Documentation/trace/ftrace.rst: Before 4.1, all ftrace tracing control files were within the debugfs file system, which is typically located at /sys/kernel/debug/tracing. For backward compatibility, when mounting the debugfs file system, the tracefs file system will be automatically mounted at: /sys/kernel/debug/tracing Update the visl decoder driver documentation to use this tracefs path. Signed-off-by: Ross Zwisler Reviewed-by: Masami Hiramatsu (Google) Reviewed-by: Steven Rostedt (Google) Signed-off-by: Hans Verkuil --- Documentation/admin-guide/media/visl.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/admin-guide/media/visl.rst b/Documentation/admin-guide/media/visl.rst index 7d2dc78341c93..4328c6c72d305 100644 --- a/Documentation/admin-guide/media/visl.rst +++ b/Documentation/admin-guide/media/visl.rst @@ -78,7 +78,7 @@ The trace events are defined on a per-codec basis, e.g.: .. code-block:: bash - $ ls /sys/kernel/debug/tracing/events/ | grep visl + $ ls /sys/kernel/tracing/events/ | grep visl visl_fwht_controls visl_h264_controls visl_hevc_controls @@ -90,13 +90,13 @@ For example, in order to dump HEVC SPS data: .. code-block:: bash - $ echo 1 > /sys/kernel/debug/tracing/events/visl_hevc_controls/v4l2_ctrl_hevc_sps/enable + $ echo 1 > /sys/kernel/tracing/events/visl_hevc_controls/v4l2_ctrl_hevc_sps/enable The SPS data will be dumped to the trace buffer, i.e.: .. code-block:: bash - $ cat /sys/kernel/debug/tracing/trace + $ cat /sys/kernel/tracing/trace video_parameter_set_id 0 seq_parameter_set_id 0 pic_width_in_luma_samples 1920 -- GitLab From 36fe515c1a3cd5eac148e8a591a82108d92d5522 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Mon, 11 Sep 2023 20:46:12 +0200 Subject: [PATCH 0461/1451] media: cedrus: Fix clock/reset sequence According to H6 user manual, resets should always be de-asserted before clocks are enabled. This is also consistent with vendor driver. Fixes: d5aecd289bab ("media: cedrus: Implement runtime PM") Signed-off-by: Jernej Skrabec Acked-by: Paul Kocialkowski Signed-off-by: Hans Verkuil --- .../staging/media/sunxi/cedrus/cedrus_hw.c | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c index b696bf884cbd6..32af0e96e762b 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c @@ -172,12 +172,12 @@ int cedrus_hw_suspend(struct device *device) { struct cedrus_dev *dev = dev_get_drvdata(device); - reset_control_assert(dev->rstc); - clk_disable_unprepare(dev->ram_clk); clk_disable_unprepare(dev->mod_clk); clk_disable_unprepare(dev->ahb_clk); + reset_control_assert(dev->rstc); + return 0; } @@ -186,11 +186,18 @@ int cedrus_hw_resume(struct device *device) struct cedrus_dev *dev = dev_get_drvdata(device); int ret; + ret = reset_control_reset(dev->rstc); + if (ret) { + dev_err(dev->dev, "Failed to apply reset\n"); + + return ret; + } + ret = clk_prepare_enable(dev->ahb_clk); if (ret) { dev_err(dev->dev, "Failed to enable AHB clock\n"); - return ret; + goto err_rst; } ret = clk_prepare_enable(dev->mod_clk); @@ -207,21 +214,14 @@ int cedrus_hw_resume(struct device *device) goto err_mod_clk; } - ret = reset_control_reset(dev->rstc); - if (ret) { - dev_err(dev->dev, "Failed to apply reset\n"); - - goto err_ram_clk; - } - return 0; -err_ram_clk: - clk_disable_unprepare(dev->ram_clk); err_mod_clk: clk_disable_unprepare(dev->mod_clk); err_ahb_clk: clk_disable_unprepare(dev->ahb_clk); +err_rst: + reset_control_assert(dev->rstc); return ret; } -- GitLab From b622e46690eb34a738bb295308f83c253b78afe0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 22 Sep 2023 10:04:19 +0200 Subject: [PATCH 0462/1451] media: i2c: drop check because i2c_unregister_device() is NULL safe No need to check the argument of i2c_unregister_device() because the function itself does it. Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/i2c/rdacm20.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c index f4e2e2f3972a9..b4647bda8c21f 100644 --- a/drivers/media/i2c/rdacm20.c +++ b/drivers/media/i2c/rdacm20.c @@ -625,8 +625,7 @@ static int rdacm20_probe(struct i2c_client *client) v4l2_ctrl_handler_free(&dev->ctrls); error: media_entity_cleanup(&dev->sd.entity); - if (dev->sensor) - i2c_unregister_device(dev->sensor); + i2c_unregister_device(dev->sensor); dev_err(&client->dev, "probe failed\n"); -- GitLab From 4b910840f9f3f5e04c98cbca5b0229d0575a407e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 22 Sep 2023 10:04:20 +0200 Subject: [PATCH 0463/1451] media: dvb-frontends: drop check because i2c_unregister_device() is NULL safe No need to check the argument of i2c_unregister_device() because the function itself does it. Signed-off-by: Wolfram Sang Reviewed-by: Kieran Bingham Reviewed-by: Geert Uytterhoeven Signed-off-by: Hans Verkuil --- drivers/media/dvb-frontends/m88ds3103.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index cf037b61b226b..26c67ef05d135 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -1920,8 +1920,7 @@ static void m88ds3103_remove(struct i2c_client *client) dev_dbg(&client->dev, "\n"); - if (dev->dt_client) - i2c_unregister_device(dev->dt_client); + i2c_unregister_device(dev->dt_client); i2c_mux_del_adapters(dev->muxc); -- GitLab From 678e8d804149038e2356aabba9d4c9cf7a19418a Mon Sep 17 00:00:00 2001 From: Ken Lin Date: Thu, 5 Oct 2023 09:38:40 +0800 Subject: [PATCH 0464/1451] media: platform: cros-ec: Rename conns array for the match table Rename conns array to port_**_conns, ** is the ports which support cec. ex: dibbi_conns support Port D and B will be renamed to port_db_conns. Make it much cleaner and readable. Signed-off-by: Ken Lin Signed-off-by: Hans Verkuil --- .../media/cec/platform/cros-ec/cros-ec-cec.c | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index 920aed0d19295..dbee25b138ff9 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -294,34 +294,34 @@ struct cec_dmi_match { const char *const *conns; }; -static const char *const fizz_conns[] = { "Port B", NULL }; -static const char *const dibbi_conns[] = { "Port D", "Port B", NULL }; -static const char *const constitution_conns[] = { "Port B", "Port A", NULL }; -static const char *const boxy_conns[] = { "Port D", NULL }; +static const char *const port_b_conns[] = { "Port B", NULL }; +static const char *const port_db_conns[] = { "Port D", "Port B", NULL }; +static const char *const port_ba_conns[] = { "Port B", "Port A", NULL }; +static const char *const port_d_conns[] = { "Port D", NULL }; static const struct cec_dmi_match cec_dmi_match_table[] = { /* Google Fizz */ - { "Google", "Fizz", "0000:00:02.0", fizz_conns }, + { "Google", "Fizz", "0000:00:02.0", port_b_conns }, /* Google Brask */ - { "Google", "Brask", "0000:00:02.0", fizz_conns }, + { "Google", "Brask", "0000:00:02.0", port_b_conns }, /* Google Moli */ - { "Google", "Moli", "0000:00:02.0", fizz_conns }, + { "Google", "Moli", "0000:00:02.0", port_b_conns }, /* Google Kinox */ - { "Google", "Kinox", "0000:00:02.0", fizz_conns }, + { "Google", "Kinox", "0000:00:02.0", port_b_conns }, /* Google Kuldax */ - { "Google", "Kuldax", "0000:00:02.0", fizz_conns }, + { "Google", "Kuldax", "0000:00:02.0", port_b_conns }, /* Google Aurash */ - { "Google", "Aurash", "0000:00:02.0", fizz_conns }, + { "Google", "Aurash", "0000:00:02.0", port_b_conns }, /* Google Gladios */ - { "Google", "Gladios", "0000:00:02.0", fizz_conns }, + { "Google", "Gladios", "0000:00:02.0", port_b_conns }, /* Google Lisbon */ - { "Google", "Lisbon", "0000:00:02.0", fizz_conns }, + { "Google", "Lisbon", "0000:00:02.0", port_b_conns }, /* Google Dibbi */ - { "Google", "Dibbi", "0000:00:02.0", dibbi_conns }, + { "Google", "Dibbi", "0000:00:02.0", port_db_conns }, /* Google Constitution */ - { "Google", "Constitution", "0000:00:02.0", constitution_conns }, + { "Google", "Constitution", "0000:00:02.0", port_ba_conns }, /* Google Boxy */ - { "Google", "Boxy", "0000:00:02.0", boxy_conns }, + { "Google", "Boxy", "0000:00:02.0", port_d_conns }, }; static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, -- GitLab From cd5c11d5aacdb7eda2acc6ee57d442b48f300858 Mon Sep 17 00:00:00 2001 From: Ken Lin Date: Thu, 5 Oct 2023 09:38:41 +0800 Subject: [PATCH 0465/1451] media: platform: cros-ec: Add Taranza to the match table Taranza has two HDMI ports which support CEC: Port D is EC port 0 Port B is EC port 1 Signed-off-by: Ken Lin Signed-off-by: Hans Verkuil --- drivers/media/cec/platform/cros-ec/cros-ec-cec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index dbee25b138ff9..42dde3f0dbdef 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -322,6 +322,8 @@ static const struct cec_dmi_match cec_dmi_match_table[] = { { "Google", "Constitution", "0000:00:02.0", port_ba_conns }, /* Google Boxy */ { "Google", "Boxy", "0000:00:02.0", port_d_conns }, + /* Google Taranza */ + { "Google", "Taranza", "0000:00:02.0", port_db_conns }, }; static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, -- GitLab From 0308483f6674d5d4e31deb8892d393b0aecd1ed3 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 19 Sep 2023 14:04:47 +0300 Subject: [PATCH 0466/1451] media: ov9282: Assign maintenance to Dave The current maintainers won't be looking after this driver anymore. Dave offered to take over the driver, assign maintenance to him. Signed-off-by: Sakari Ailus Acked-by: Dave Stevenson Signed-off-by: Hans Verkuil --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index bba09f9d01418..bcbc7c2b9c3f8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15881,8 +15881,7 @@ F: Documentation/devicetree/bindings/media/i2c/ovti,ov8858.yaml F: drivers/media/i2c/ov8858.c OMNIVISION OV9282 SENSOR DRIVER -M: Paul J. Murphy -M: Daniele Alessandrelli +M: Dave Stevenson L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git -- GitLab From 59ac78dcd17ccfe362229d5538ac9c1d00456e15 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 19 Sep 2023 14:06:06 +0300 Subject: [PATCH 0467/1451] media: imx412: Orphan the driver The current maintainers won't be looking after this driver anymore. Mark it orphan. Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- MAINTAINERS | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index bcbc7c2b9c3f8..a9d4f734702bb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20045,10 +20045,8 @@ T: git git://linuxtv.org/media_tree.git F: drivers/media/i2c/imx355.c SONY IMX412 SENSOR DRIVER -M: Paul J. Murphy -M: Daniele Alessandrelli L: linux-media@vger.kernel.org -S: Maintained +S: Orphan T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml F: drivers/media/i2c/imx412.c -- GitLab From 5b0e91fd477d0fbfac6989cbf26071c28f21bfe4 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 19 Sep 2023 14:09:32 +0300 Subject: [PATCH 0468/1451] media: imx335: Orphan the driver The current maintainers won't be looking after this driver anymore. Mark it orphan. Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- MAINTAINERS | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index a9d4f734702bb..85c817eae9aeb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20029,10 +20029,8 @@ F: Documentation/devicetree/bindings/media/i2c/sony,imx334.yaml F: drivers/media/i2c/imx334.c SONY IMX335 SENSOR DRIVER -M: Paul J. Murphy -M: Daniele Alessandrelli L: linux-media@vger.kernel.org -S: Maintained +S: Orphan T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml F: drivers/media/i2c/imx335.c -- GitLab From 17c74cb89706654713bfa817820b2b981771c104 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 19 Sep 2023 14:09:57 +0300 Subject: [PATCH 0469/1451] media: imx334: Orphan the driver The current maintainers won't be looking after this driver anymore. Mark it orphan. Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- MAINTAINERS | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 85c817eae9aeb..985670c74cf06 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20020,10 +20020,8 @@ T: git git://linuxtv.org/media_tree.git F: drivers/media/i2c/imx319.c SONY IMX334 SENSOR DRIVER -M: Paul J. Murphy -M: Daniele Alessandrelli L: linux-media@vger.kernel.org -S: Maintained +S: Orphan T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/sony,imx334.yaml F: drivers/media/i2c/imx334.c -- GitLab From 206d8a9b36d32877db1952bb4afd357ba4a9cb88 Mon Sep 17 00:00:00 2001 From: Bingbu Cao Date: Mon, 18 Sep 2023 10:58:12 +0800 Subject: [PATCH 0470/1451] media: i2c/hi556: add a new mode 1296x722 settings Add a new mode - 16:9 resolution 1296x722 for hi556. Signed-off-by: Bingbu Cao Signed-off-by: Qingwu Zhang Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/hi556.c | 64 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/hi556.c b/drivers/media/i2c/hi556.c index e6e7049108e75..f6ea9b7b97005 100644 --- a/drivers/media/i2c/hi556.c +++ b/drivers/media/i2c/hi556.c @@ -477,6 +477,50 @@ static const struct hi556_reg mode_1296x972_regs[] = { {0x0958, 0xbb80}, }; +static const struct hi556_reg mode_1296x722_regs[] = { + {0x0a00, 0x0000}, + {0x0b0a, 0x8259}, + {0x0f30, 0x5b15}, + {0x0f32, 0x7167}, + {0x004a, 0x0100}, + {0x004c, 0x0000}, + {0x004e, 0x0100}, + {0x000c, 0x0122}, + {0x0008, 0x0b00}, + {0x005a, 0x0404}, + {0x0012, 0x000c}, + {0x0018, 0x0a33}, + {0x0022, 0x0008}, + {0x0028, 0x0017}, + {0x0024, 0x0022}, + {0x002a, 0x002b}, + {0x0026, 0x012a}, + {0x002c, 0x06cf}, + {0x002e, 0x3311}, + {0x0030, 0x3311}, + {0x0032, 0x3311}, + {0x0006, 0x0814}, + {0x0a22, 0x0000}, + {0x0a12, 0x0510}, + {0x0a14, 0x02d2}, + {0x003e, 0x0000}, + {0x0074, 0x0812}, + {0x0070, 0x0409}, + {0x0804, 0x0308}, + {0x0806, 0x0100}, + {0x0a04, 0x016a}, + {0x090c, 0x09c0}, + {0x090e, 0x0010}, + {0x0902, 0x4319}, + {0x0914, 0xc106}, + {0x0916, 0x040e}, + {0x0918, 0x0304}, + {0x091a, 0x0708}, + {0x091c, 0x0e06}, + {0x091e, 0x0300}, + {0x0958, 0xbb80}, +}; + static const char * const hi556_test_pattern_menu[] = { "Disabled", "Solid Colour", @@ -556,7 +600,25 @@ static const struct hi556_mode supported_modes[] = { .regs = mode_1296x972_regs, }, .link_freq_index = HI556_LINK_FREQ_437MHZ_INDEX, - } + }, + { + .width = 1296, + .height = 722, + .crop = { + .left = HI556_PIXEL_ARRAY_LEFT, + .top = 250, + .width = HI556_PIXEL_ARRAY_WIDTH, + .height = 1444 + }, + .fll_def = HI556_FLL_30FPS, + .fll_min = HI556_FLL_30FPS_MIN, + .llp = 0x0b00, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1296x722_regs), + .regs = mode_1296x722_regs, + }, + .link_freq_index = HI556_LINK_FREQ_437MHZ_INDEX, + }, }; struct hi556 { -- GitLab From e00d0d9e74fe2b1dccea3b8ee1c9593dba8f6117 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 20 Sep 2023 20:11:53 +0300 Subject: [PATCH 0471/1451] media: dt-bindings: media: i2c: Add MT9M114 camera sensor binding Add device tree binding for the onsemi MT9M114 CMOS camera sensor. Signed-off-by: Laurent Pinchart Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../bindings/media/i2c/onnn,mt9m114.yaml | 114 ++++++++++++++++++ MAINTAINERS | 7 ++ 2 files changed, 121 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/i2c/onnn,mt9m114.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/onnn,mt9m114.yaml b/Documentation/devicetree/bindings/media/i2c/onnn,mt9m114.yaml new file mode 100644 index 0000000000000..f6b87892068ac --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/onnn,mt9m114.yaml @@ -0,0 +1,114 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/onnn,mt9m114.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: onsemi 1/6-inch 720p CMOS Digital Image Sensor + +maintainers: + - Laurent Pinchart + +description: |- + The onsemi MT9M114 is a 1/6-inch 720p (1.26 Mp) CMOS digital image sensor + with an active pixel-array size of 1296H x 976V. It is programmable through + an I2C interface and outputs image data over a 8-bit parallel or 1-lane MIPI + CSI-2 connection. + +properties: + compatible: + const: onnn,mt9m114 + + reg: + description: I2C device address + enum: + - 0x48 + - 0x5d + + clocks: + description: EXTCLK clock signal + maxItems: 1 + + vdd-supply: + description: + Core digital voltage supply, 1.8V + + vddio-supply: + description: + I/O digital voltage supply, 1.8V or 2.8V + + vaa-supply: + description: + Analog voltage supply, 2.8V + + reset-gpios: + description: |- + Reference to the GPIO connected to the RESET_BAR pin, if any (active + low). + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + additionalProperties: false + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + additionalProperties: false + + properties: + bus-type: + enum: [4, 5, 6] + + link-frequencies: true + remote-endpoint: true + + # The number and mapping of lanes (for CSI-2), and the bus width and + # signal polarities (for parallel and BT.656) are fixed and must not + # be specified. + + required: + - bus-type + - link-frequencies + +required: + - compatible + - reg + - clocks + - vdd-supply + - vddio-supply + - vaa-supply + - port + +additionalProperties: false + +examples: + - | + #include + #include + + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + sensor@48 { + compatible = "onnn,mt9m114"; + reg = <0x48>; + + clocks = <&clk24m 0>; + + reset-gpios = <&gpio5 21 GPIO_ACTIVE_LOW>; + + vddio-supply = <®_cam_1v8>; + vdd-supply = <®_cam_1v8>; + vaa-supply = <®_2p8v>; + + port { + endpoint { + bus-type = ; + link-frequencies = /bits/ 64 <384000000>; + remote-endpoint = <&mipi_csi_in>; + }; + }; + }; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index 985670c74cf06..c55e13029e2d0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14558,6 +14558,13 @@ L: linux-mtd@lists.infradead.org S: Maintained F: drivers/mtd/devices/docg3* +MT9M114 ONSEMI SENSOR DRIVER +M: Laurent Pinchart +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/onnn,mt9m114.yaml + MT9P031 APTINA CAMERA SENSOR M: Laurent Pinchart L: linux-media@vger.kernel.org -- GitLab From 24d756e914fc3418bad7897b0657aefa9ef848e8 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 20 Sep 2023 20:11:54 +0300 Subject: [PATCH 0472/1451] media: i2c: Add driver for onsemi MT9M114 camera sensor The MT9M114 is a CMOS camera sensor that combines a 1296x976 pixel array with a 10-bit dynamic range together with an internal ISP. The driver exposes two subdevs, one for the pixel array and one for the ISP (named IFP for Image Flow Processor). Major supported features are - Full configuration of analog crop and binning in the pixel array - Full configuration of scaling in the ISP - Automatic exposure and white balance - Manual exposure and analog gain - Horizontal and vertical flip Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- MAINTAINERS | 1 + drivers/media/i2c/Kconfig | 10 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/mt9m114.c | 2481 +++++++++++++++++++++++++++++++++++ 4 files changed, 2493 insertions(+) create mode 100644 drivers/media/i2c/mt9m114.c diff --git a/MAINTAINERS b/MAINTAINERS index c55e13029e2d0..83a0c7f3826b9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14564,6 +14564,7 @@ L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/onnn,mt9m114.yaml +F: drivers/media/i2c/mt9m114.c MT9P031 APTINA CAMERA SENSOR M: Laurent Pinchart diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 74ff833ff48ca..897d02f0b5523 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -215,6 +215,16 @@ config VIDEO_MT9M111 This driver supports MT9M111, MT9M112 and MT9M131 cameras from Micron/Aptina +config VIDEO_MT9M114 + tristate "onsemi MT9M114 sensor support" + select V4L2_CCI_I2C + help + This is a Video4Linux2 sensor-level driver for the onsemi MT9M114 + camera. + + To compile this driver as a module, choose M here: the + module will be called mt9m114. + config VIDEO_MT9P031 tristate "Aptina MT9P031 support" select VIDEO_APTINA_PLL diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 80b00d39b48f0..f5010f80a21f3 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o obj-$(CONFIG_VIDEO_MT9M111) += mt9m111.o +obj-$(CONFIG_VIDEO_MT9M114) += mt9m114.o obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o obj-$(CONFIG_VIDEO_MT9T112) += mt9t112.o obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o diff --git a/drivers/media/i2c/mt9m114.c b/drivers/media/i2c/mt9m114.c new file mode 100644 index 0000000000000..dae675e523901 --- /dev/null +++ b/drivers/media/i2c/mt9m114.c @@ -0,0 +1,2481 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * mt9m114.c onsemi MT9M114 sensor driver + * + * Copyright (c) 2020-2023 Laurent Pinchart + * Copyright (c) 2012 Analog Devices Inc. + * + * Almost complete rewrite of work by Scott Jiang + * itself based on work from Andrew Chew . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Sysctl registers */ +#define MT9M114_CHIP_ID CCI_REG16(0x0000) +#define MT9M114_COMMAND_REGISTER CCI_REG16(0x0080) +#define MT9M114_COMMAND_REGISTER_APPLY_PATCH BIT(0) +#define MT9M114_COMMAND_REGISTER_SET_STATE BIT(1) +#define MT9M114_COMMAND_REGISTER_REFRESH BIT(2) +#define MT9M114_COMMAND_REGISTER_WAIT_FOR_EVENT BIT(3) +#define MT9M114_COMMAND_REGISTER_OK BIT(15) +#define MT9M114_RESET_AND_MISC_CONTROL CCI_REG16(0x001a) +#define MT9M114_RESET_SOC BIT(0) +#define MT9M114_PAD_SLEW CCI_REG16(0x001e) +#define MT9M114_PAD_CONTROL CCI_REG16(0x0032) + +/* XDMA registers */ +#define MT9M114_ACCESS_CTL_STAT CCI_REG16(0x0982) +#define MT9M114_PHYSICAL_ADDRESS_ACCESS CCI_REG16(0x098a) +#define MT9M114_LOGICAL_ADDRESS_ACCESS CCI_REG16(0x098e) + +/* Sensor Core registers */ +#define MT9M114_COARSE_INTEGRATION_TIME CCI_REG16(0x3012) +#define MT9M114_FINE_INTEGRATION_TIME CCI_REG16(0x3014) +#define MT9M114_RESET_REGISTER CCI_REG16(0x301a) +#define MT9M114_RESET_REGISTER_LOCK_REG BIT(3) +#define MT9M114_RESET_REGISTER_MASK_BAD BIT(9) +#define MT9M114_FLASH CCI_REG16(0x3046) +#define MT9M114_GREEN1_GAIN CCI_REG16(0x3056) +#define MT9M114_BLUE_GAIN CCI_REG16(0x3058) +#define MT9M114_RED_GAIN CCI_REG16(0x305a) +#define MT9M114_GREEN2_GAIN CCI_REG16(0x305c) +#define MT9M114_GLOBAL_GAIN CCI_REG16(0x305e) +#define MT9M114_GAIN_DIGITAL_GAIN(n) ((n) << 12) +#define MT9M114_GAIN_DIGITAL_GAIN_MASK (0xf << 12) +#define MT9M114_GAIN_ANALOG_GAIN(n) ((n) << 0) +#define MT9M114_GAIN_ANALOG_GAIN_MASK (0xff << 0) +#define MT9M114_CUSTOMER_REV CCI_REG16(0x31fe) + +/* Monitor registers */ +#define MT9M114_MON_MAJOR_VERSION CCI_REG16(0x8000) +#define MT9M114_MON_MINOR_VERSION CCI_REG16(0x8002) +#define MT9M114_MON_RELEASE_VERSION CCI_REG16(0x8004) + +/* Auto-Exposure Track registers */ +#define MT9M114_AE_TRACK_ALGO CCI_REG16(0xa804) +#define MT9M114_AE_TRACK_EXEC_AUTOMATIC_EXPOSURE BIT(0) +#define MT9M114_AE_TRACK_AE_TRACKING_DAMPENING_SPEED CCI_REG8(0xa80a) + +/* Color Correction Matrix registers */ +#define MT9M114_CCM_ALGO CCI_REG16(0xb404) +#define MT9M114_CCM_EXEC_CALC_CCM_MATRIX BIT(4) +#define MT9M114_CCM_DELTA_GAIN CCI_REG8(0xb42a) + +/* Camera Control registers */ +#define MT9M114_CAM_SENSOR_CFG_Y_ADDR_START CCI_REG16(0xc800) +#define MT9M114_CAM_SENSOR_CFG_X_ADDR_START CCI_REG16(0xc802) +#define MT9M114_CAM_SENSOR_CFG_Y_ADDR_END CCI_REG16(0xc804) +#define MT9M114_CAM_SENSOR_CFG_X_ADDR_END CCI_REG16(0xc806) +#define MT9M114_CAM_SENSOR_CFG_PIXCLK CCI_REG32(0xc808) +#define MT9M114_CAM_SENSOR_CFG_ROW_SPEED CCI_REG16(0xc80c) +#define MT9M114_CAM_SENSOR_CFG_FINE_INTEG_TIME_MIN CCI_REG16(0xc80e) +#define MT9M114_CAM_SENSOR_CFG_FINE_INTEG_TIME_MAX CCI_REG16(0xc810) +#define MT9M114_CAM_SENSOR_CFG_FRAME_LENGTH_LINES CCI_REG16(0xc812) +#define MT9M114_CAM_SENSOR_CFG_FRAME_LENGTH_LINES_MAX 65535 +#define MT9M114_CAM_SENSOR_CFG_LINE_LENGTH_PCK CCI_REG16(0xc814) +#define MT9M114_CAM_SENSOR_CFG_LINE_LENGTH_PCK_MAX 8191 +#define MT9M114_CAM_SENSOR_CFG_FINE_CORRECTION CCI_REG16(0xc816) +#define MT9M114_CAM_SENSOR_CFG_CPIPE_LAST_ROW CCI_REG16(0xc818) +#define MT9M114_CAM_SENSOR_CFG_REG_0_DATA CCI_REG16(0xc826) +#define MT9M114_CAM_SENSOR_CONTROL_READ_MODE CCI_REG16(0xc834) +#define MT9M114_CAM_SENSOR_CONTROL_HORZ_MIRROR_EN BIT(0) +#define MT9M114_CAM_SENSOR_CONTROL_VERT_FLIP_EN BIT(1) +#define MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_NORMAL (0 << 4) +#define MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_SKIPPING (1 << 4) +#define MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_AVERAGE (2 << 4) +#define MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_SUMMING (3 << 4) +#define MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_MASK (3 << 4) +#define MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_NORMAL (0 << 8) +#define MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_SKIPPING (1 << 8) +#define MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_SUMMING (3 << 8) +#define MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_MASK (3 << 8) +#define MT9M114_CAM_SENSOR_CONTROL_ANALOG_GAIN CCI_REG16(0xc836) +#define MT9M114_CAM_SENSOR_CONTROL_COARSE_INTEGRATION_TIME CCI_REG16(0xc83c) +#define MT9M114_CAM_SENSOR_CONTROL_FINE_INTEGRATION_TIME CCI_REG16(0xc83e) +#define MT9M114_CAM_MODE_SELECT CCI_REG8(0xc84c) +#define MT9M114_CAM_MODE_SELECT_NORMAL (0 << 0) +#define MT9M114_CAM_MODE_SELECT_LENS_CALIBRATION (1 << 0) +#define MT9M114_CAM_MODE_SELECT_TEST_PATTERN (2 << 0) +#define MT9M114_CAM_MODE_TEST_PATTERN_SELECT CCI_REG8(0xc84d) +#define MT9M114_CAM_MODE_TEST_PATTERN_SELECT_SOLID (1 << 0) +#define MT9M114_CAM_MODE_TEST_PATTERN_SELECT_SOLID_BARS (4 << 0) +#define MT9M114_CAM_MODE_TEST_PATTERN_SELECT_RANDOM (5 << 0) +#define MT9M114_CAM_MODE_TEST_PATTERN_SELECT_FADING_BARS (8 << 0) +#define MT9M114_CAM_MODE_TEST_PATTERN_SELECT_WALKING_1S_10B (10 << 0) +#define MT9M114_CAM_MODE_TEST_PATTERN_SELECT_WALKING_1S_8B (11 << 0) +#define MT9M114_CAM_MODE_TEST_PATTERN_RED CCI_REG16(0xc84e) +#define MT9M114_CAM_MODE_TEST_PATTERN_GREEN CCI_REG16(0xc850) +#define MT9M114_CAM_MODE_TEST_PATTERN_BLUE CCI_REG16(0xc852) +#define MT9M114_CAM_CROP_WINDOW_XOFFSET CCI_REG16(0xc854) +#define MT9M114_CAM_CROP_WINDOW_YOFFSET CCI_REG16(0xc856) +#define MT9M114_CAM_CROP_WINDOW_WIDTH CCI_REG16(0xc858) +#define MT9M114_CAM_CROP_WINDOW_HEIGHT CCI_REG16(0xc85a) +#define MT9M114_CAM_CROP_CROPMODE CCI_REG8(0xc85c) +#define MT9M114_CAM_CROP_MODE_AE_AUTO_CROP_EN BIT(0) +#define MT9M114_CAM_CROP_MODE_AWB_AUTO_CROP_EN BIT(1) +#define MT9M114_CAM_OUTPUT_WIDTH CCI_REG16(0xc868) +#define MT9M114_CAM_OUTPUT_HEIGHT CCI_REG16(0xc86a) +#define MT9M114_CAM_OUTPUT_FORMAT CCI_REG16(0xc86c) +#define MT9M114_CAM_OUTPUT_FORMAT_SWAP_RED_BLUE BIT(0) +#define MT9M114_CAM_OUTPUT_FORMAT_SWAP_BYTES BIT(1) +#define MT9M114_CAM_OUTPUT_FORMAT_MONO_ENABLE BIT(2) +#define MT9M114_CAM_OUTPUT_FORMAT_BT656_ENABLE BIT(3) +#define MT9M114_CAM_OUTPUT_FORMAT_BT656_CROP_SCALE_DISABLE BIT(4) +#define MT9M114_CAM_OUTPUT_FORMAT_FVLV_DISABLE BIT(5) +#define MT9M114_CAM_OUTPUT_FORMAT_FORMAT_YUV (0 << 8) +#define MT9M114_CAM_OUTPUT_FORMAT_FORMAT_RGB (1 << 8) +#define MT9M114_CAM_OUTPUT_FORMAT_FORMAT_BAYER (2 << 8) +#define MT9M114_CAM_OUTPUT_FORMAT_FORMAT_NONE (3 << 8) +#define MT9M114_CAM_OUTPUT_FORMAT_FORMAT_MASK (3 << 8) +#define MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_RAWR10 (0 << 10) +#define MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_PRELSC_8_2 (1 << 10) +#define MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_POSTLSC_8_2 (2 << 10) +#define MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_PROCESSED8 (3 << 10) +#define MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_MASK (3 << 10) +#define MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_565RGB (0 << 12) +#define MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_555RGB (1 << 12) +#define MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_444xRGB (2 << 12) +#define MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_444RGBx (3 << 12) +#define MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_MASK (3 << 12) +#define MT9M114_CAM_OUTPUT_FORMAT_YUV CCI_REG16(0xc86e) +#define MT9M114_CAM_OUTPUT_FORMAT_YUV_CLIP BIT(5) +#define MT9M114_CAM_OUTPUT_FORMAT_YUV_AUV_OFFSET BIT(4) +#define MT9M114_CAM_OUTPUT_FORMAT_YUV_SELECT_601 BIT(3) +#define MT9M114_CAM_OUTPUT_FORMAT_YUV_NORMALISE BIT(2) +#define MT9M114_CAM_OUTPUT_FORMAT_YUV_SAMPLING_EVEN_UV (0 << 0) +#define MT9M114_CAM_OUTPUT_FORMAT_YUV_SAMPLING_ODD_UV (1 << 0) +#define MT9M114_CAM_OUTPUT_FORMAT_YUV_SAMPLING_EVENU_ODDV (2 << 0) +#define MT9M114_CAM_OUTPUT_Y_OFFSET CCI_REG8(0xc870) +#define MT9M114_CAM_AET_AEMODE CCI_REG8(0xc878) +#define MT9M114_CAM_AET_EXEC_SET_INDOOR BIT(0) +#define MT9M114_CAM_AET_DISCRETE_FRAMERATE BIT(1) +#define MT9M114_CAM_AET_ADAPTATIVE_TARGET_LUMA BIT(2) +#define MT9M114_CAM_AET_ADAPTATIVE_SKIP_FRAMES BIT(3) +#define MT9M114_CAM_AET_SKIP_FRAMES CCI_REG8(0xc879) +#define MT9M114_CAM_AET_TARGET_AVERAGE_LUMA CCI_REG8(0xc87a) +#define MT9M114_CAM_AET_TARGET_AVERAGE_LUMA_DARK CCI_REG8(0xc87b) +#define MT9M114_CAM_AET_BLACK_CLIPPING_TARGET CCI_REG16(0xc87c) +#define MT9M114_CAM_AET_AE_MIN_VIRT_INT_TIME_PCLK CCI_REG16(0xc87e) +#define MT9M114_CAM_AET_AE_MIN_VIRT_DGAIN CCI_REG16(0xc880) +#define MT9M114_CAM_AET_AE_MAX_VIRT_DGAIN CCI_REG16(0xc882) +#define MT9M114_CAM_AET_AE_MIN_VIRT_AGAIN CCI_REG16(0xc884) +#define MT9M114_CAM_AET_AE_MAX_VIRT_AGAIN CCI_REG16(0xc886) +#define MT9M114_CAM_AET_AE_VIRT_GAIN_TH_EG CCI_REG16(0xc888) +#define MT9M114_CAM_AET_AE_EG_GATE_PERCENTAGE CCI_REG8(0xc88a) +#define MT9M114_CAM_AET_FLICKER_FREQ_HZ CCI_REG8(0xc88b) +#define MT9M114_CAM_AET_MAX_FRAME_RATE CCI_REG16(0xc88c) +#define MT9M114_CAM_AET_MIN_FRAME_RATE CCI_REG16(0xc88e) +#define MT9M114_CAM_AET_TARGET_GAIN CCI_REG16(0xc890) +#define MT9M114_CAM_AWB_CCM_L(n) CCI_REG16(0xc892 + (n) * 2) +#define MT9M114_CAM_AWB_CCM_M(n) CCI_REG16(0xc8a4 + (n) * 2) +#define MT9M114_CAM_AWB_CCM_R(n) CCI_REG16(0xc8b6 + (n) * 2) +#define MT9M114_CAM_AWB_CCM_L_RG_GAIN CCI_REG16(0xc8c8) +#define MT9M114_CAM_AWB_CCM_L_BG_GAIN CCI_REG16(0xc8ca) +#define MT9M114_CAM_AWB_CCM_M_RG_GAIN CCI_REG16(0xc8cc) +#define MT9M114_CAM_AWB_CCM_M_BG_GAIN CCI_REG16(0xc8ce) +#define MT9M114_CAM_AWB_CCM_R_RG_GAIN CCI_REG16(0xc8d0) +#define MT9M114_CAM_AWB_CCM_R_BG_GAIN CCI_REG16(0xc8d2) +#define MT9M114_CAM_AWB_CCM_L_CTEMP CCI_REG16(0xc8d4) +#define MT9M114_CAM_AWB_CCM_M_CTEMP CCI_REG16(0xc8d6) +#define MT9M114_CAM_AWB_CCM_R_CTEMP CCI_REG16(0xc8d8) +#define MT9M114_CAM_AWB_AWB_XSCALE CCI_REG8(0xc8f2) +#define MT9M114_CAM_AWB_AWB_YSCALE CCI_REG8(0xc8f3) +#define MT9M114_CAM_AWB_AWB_WEIGHTS(n) CCI_REG16(0xc8f4 + (n) * 2) +#define MT9M114_CAM_AWB_AWB_XSHIFT_PRE_ADJ CCI_REG16(0xc904) +#define MT9M114_CAM_AWB_AWB_YSHIFT_PRE_ADJ CCI_REG16(0xc906) +#define MT9M114_CAM_AWB_AWBMODE CCI_REG8(0xc909) +#define MT9M114_CAM_AWB_MODE_AUTO BIT(1) +#define MT9M114_CAM_AWB_MODE_EXCLUSIVE_AE BIT(0) +#define MT9M114_CAM_AWB_K_R_L CCI_REG8(0xc90c) +#define MT9M114_CAM_AWB_K_G_L CCI_REG8(0xc90d) +#define MT9M114_CAM_AWB_K_B_L CCI_REG8(0xc90e) +#define MT9M114_CAM_AWB_K_R_R CCI_REG8(0xc90f) +#define MT9M114_CAM_AWB_K_G_R CCI_REG8(0xc910) +#define MT9M114_CAM_AWB_K_B_R CCI_REG8(0xc911) +#define MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XSTART CCI_REG16(0xc914) +#define MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YSTART CCI_REG16(0xc916) +#define MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XEND CCI_REG16(0xc918) +#define MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YEND CCI_REG16(0xc91a) +#define MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XSTART CCI_REG16(0xc91c) +#define MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YSTART CCI_REG16(0xc91e) +#define MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XEND CCI_REG16(0xc920) +#define MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YEND CCI_REG16(0xc922) +#define MT9M114_CAM_LL_LLMODE CCI_REG16(0xc924) +#define MT9M114_CAM_LL_START_BRIGHTNESS CCI_REG16(0xc926) +#define MT9M114_CAM_LL_STOP_BRIGHTNESS CCI_REG16(0xc928) +#define MT9M114_CAM_LL_START_SATURATION CCI_REG8(0xc92a) +#define MT9M114_CAM_LL_END_SATURATION CCI_REG8(0xc92b) +#define MT9M114_CAM_LL_START_DESATURATION CCI_REG8(0xc92c) +#define MT9M114_CAM_LL_END_DESATURATION CCI_REG8(0xc92d) +#define MT9M114_CAM_LL_START_DEMOSAICING CCI_REG8(0xc92e) +#define MT9M114_CAM_LL_START_AP_GAIN CCI_REG8(0xc92f) +#define MT9M114_CAM_LL_START_AP_THRESH CCI_REG8(0xc930) +#define MT9M114_CAM_LL_STOP_DEMOSAICING CCI_REG8(0xc931) +#define MT9M114_CAM_LL_STOP_AP_GAIN CCI_REG8(0xc932) +#define MT9M114_CAM_LL_STOP_AP_THRESH CCI_REG8(0xc933) +#define MT9M114_CAM_LL_START_NR_RED CCI_REG8(0xc934) +#define MT9M114_CAM_LL_START_NR_GREEN CCI_REG8(0xc935) +#define MT9M114_CAM_LL_START_NR_BLUE CCI_REG8(0xc936) +#define MT9M114_CAM_LL_START_NR_THRESH CCI_REG8(0xc937) +#define MT9M114_CAM_LL_STOP_NR_RED CCI_REG8(0xc938) +#define MT9M114_CAM_LL_STOP_NR_GREEN CCI_REG8(0xc939) +#define MT9M114_CAM_LL_STOP_NR_BLUE CCI_REG8(0xc93a) +#define MT9M114_CAM_LL_STOP_NR_THRESH CCI_REG8(0xc93b) +#define MT9M114_CAM_LL_START_CONTRAST_BM CCI_REG16(0xc93c) +#define MT9M114_CAM_LL_STOP_CONTRAST_BM CCI_REG16(0xc93e) +#define MT9M114_CAM_LL_GAMMA CCI_REG16(0xc940) +#define MT9M114_CAM_LL_START_CONTRAST_GRADIENT CCI_REG8(0xc942) +#define MT9M114_CAM_LL_STOP_CONTRAST_GRADIENT CCI_REG8(0xc943) +#define MT9M114_CAM_LL_START_CONTRAST_LUMA_PERCENTAGE CCI_REG8(0xc944) +#define MT9M114_CAM_LL_STOP_CONTRAST_LUMA_PERCENTAGE CCI_REG8(0xc945) +#define MT9M114_CAM_LL_START_GAIN_METRIC CCI_REG16(0xc946) +#define MT9M114_CAM_LL_STOP_GAIN_METRIC CCI_REG16(0xc948) +#define MT9M114_CAM_LL_START_FADE_TO_BLACK_LUMA CCI_REG16(0xc94a) +#define MT9M114_CAM_LL_STOP_FADE_TO_BLACK_LUMA CCI_REG16(0xc94c) +#define MT9M114_CAM_LL_CLUSTER_DC_TH_BM CCI_REG16(0xc94e) +#define MT9M114_CAM_LL_CLUSTER_DC_GATE_PERCENTAGE CCI_REG8(0xc950) +#define MT9M114_CAM_LL_SUMMING_SENSITIVITY_FACTOR CCI_REG8(0xc951) +#define MT9M114_CAM_LL_START_TARGET_LUMA_BM CCI_REG16(0xc952) +#define MT9M114_CAM_LL_STOP_TARGET_LUMA_BM CCI_REG16(0xc954) +#define MT9M114_CAM_PGA_PGA_CONTROL CCI_REG16(0xc95e) +#define MT9M114_CAM_SYSCTL_PLL_ENABLE CCI_REG8(0xc97e) +#define MT9M114_CAM_SYSCTL_PLL_ENABLE_VALUE BIT(0) +#define MT9M114_CAM_SYSCTL_PLL_DIVIDER_M_N CCI_REG16(0xc980) +#define MT9M114_CAM_SYSCTL_PLL_DIVIDER_VALUE(m, n) (((n) << 8) | (m)) +#define MT9M114_CAM_SYSCTL_PLL_DIVIDER_P CCI_REG16(0xc982) +#define MT9M114_CAM_SYSCTL_PLL_DIVIDER_P_VALUE(p) ((p) << 8) +#define MT9M114_CAM_PORT_OUTPUT_CONTROL CCI_REG16(0xc984) +#define MT9M114_CAM_PORT_PORT_SELECT_PARALLEL (0 << 0) +#define MT9M114_CAM_PORT_PORT_SELECT_MIPI (1 << 0) +#define MT9M114_CAM_PORT_CLOCK_SLOWDOWN BIT(3) +#define MT9M114_CAM_PORT_TRUNCATE_RAW_BAYER BIT(4) +#define MT9M114_CAM_PORT_PIXCLK_GATE BIT(5) +#define MT9M114_CAM_PORT_CONT_MIPI_CLK BIT(6) +#define MT9M114_CAM_PORT_CHAN_NUM(vc) ((vc) << 8) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_HS_ZERO CCI_REG16(0xc988) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_HS_ZERO_VALUE(n) ((n) << 8) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_HS_EXIT_TRAIL CCI_REG16(0xc98a) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_HS_EXIT_VALUE(n) ((n) << 8) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_HS_TRAIL_VALUE(n) ((n) << 0) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_CLK_POST_PRE CCI_REG16(0xc98c) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_CLK_POST_VALUE(n) ((n) << 8) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_CLK_PRE_VALUE(n) ((n) << 0) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_CLK_TRAIL_ZERO CCI_REG16(0xc98e) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_CLK_TRAIL_VALUE(n) ((n) << 8) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_CLK_ZERO_VALUE(n) ((n) << 0) + +/* System Manager registers */ +#define MT9M114_SYSMGR_NEXT_STATE CCI_REG8(0xdc00) +#define MT9M114_SYSMGR_CURRENT_STATE CCI_REG8(0xdc01) +#define MT9M114_SYSMGR_CMD_STATUS CCI_REG8(0xdc02) + +/* Patch Loader registers */ +#define MT9M114_PATCHLDR_LOADER_ADDRESS CCI_REG16(0xe000) +#define MT9M114_PATCHLDR_PATCH_ID CCI_REG16(0xe002) +#define MT9M114_PATCHLDR_FIRMWARE_ID CCI_REG32(0xe004) +#define MT9M114_PATCHLDR_APPLY_STATUS CCI_REG8(0xe008) +#define MT9M114_PATCHLDR_NUM_PATCHES CCI_REG8(0xe009) +#define MT9M114_PATCHLDR_PATCH_ID_0 CCI_REG16(0xe00a) +#define MT9M114_PATCHLDR_PATCH_ID_1 CCI_REG16(0xe00c) +#define MT9M114_PATCHLDR_PATCH_ID_2 CCI_REG16(0xe00e) +#define MT9M114_PATCHLDR_PATCH_ID_3 CCI_REG16(0xe010) +#define MT9M114_PATCHLDR_PATCH_ID_4 CCI_REG16(0xe012) +#define MT9M114_PATCHLDR_PATCH_ID_5 CCI_REG16(0xe014) +#define MT9M114_PATCHLDR_PATCH_ID_6 CCI_REG16(0xe016) +#define MT9M114_PATCHLDR_PATCH_ID_7 CCI_REG16(0xe018) + +/* SYS_STATE values (for SYSMGR_NEXT_STATE and SYSMGR_CURRENT_STATE) */ +#define MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE 0x28 +#define MT9M114_SYS_STATE_STREAMING 0x31 +#define MT9M114_SYS_STATE_START_STREAMING 0x34 +#define MT9M114_SYS_STATE_ENTER_SUSPEND 0x40 +#define MT9M114_SYS_STATE_SUSPENDED 0x41 +#define MT9M114_SYS_STATE_ENTER_STANDBY 0x50 +#define MT9M114_SYS_STATE_STANDBY 0x52 +#define MT9M114_SYS_STATE_LEAVE_STANDBY 0x54 + +/* Result status of last SET_STATE comamnd */ +#define MT9M114_SET_STATE_RESULT_ENOERR 0x00 +#define MT9M114_SET_STATE_RESULT_EINVAL 0x0c +#define MT9M114_SET_STATE_RESULT_ENOSPC 0x0d + +/* + * The minimum amount of horizontal and vertical blanking is undocumented. The + * minimum values that have been seen in register lists are 303 and 38, use + * them. + * + * Set the default to achieve 1280x960 at 30fps. + */ +#define MT9M114_MIN_HBLANK 303 +#define MT9M114_MIN_VBLANK 38 +#define MT9M114_DEF_HBLANK 323 +#define MT9M114_DEF_VBLANK 39 + +#define MT9M114_DEF_FRAME_RATE 30 +#define MT9M114_MAX_FRAME_RATE 120 + +#define MT9M114_PIXEL_ARRAY_WIDTH 1296U +#define MT9M114_PIXEL_ARRAY_HEIGHT 976U + +/* + * These values are not well documented and are semi-arbitrary. The pixel array + * minimum output size is 8 pixels larger than the minimum scaler cropped input + * width to account for the demosaicing. + */ +#define MT9M114_PIXEL_ARRAY_MIN_OUTPUT_WIDTH (32U + 8U) +#define MT9M114_PIXEL_ARRAY_MIN_OUTPUT_HEIGHT (32U + 8U) +#define MT9M114_SCALER_CROPPED_INPUT_WIDTH 32U +#define MT9M114_SCALER_CROPPED_INPUT_HEIGHT 32U + +/* Indices into the mt9m114.ifp.tpg array. */ +#define MT9M114_TPG_PATTERN 0 +#define MT9M114_TPG_RED 1 +#define MT9M114_TPG_GREEN 2 +#define MT9M114_TPG_BLUE 3 + +/* ----------------------------------------------------------------------------- + * Data Structures + */ + +enum mt9m114_format_flag { + MT9M114_FMT_FLAG_PARALLEL = BIT(0), + MT9M114_FMT_FLAG_CSI2 = BIT(1), +}; + +struct mt9m114_format_info { + u32 code; + u32 output_format; + u32 flags; +}; + +struct mt9m114 { + struct i2c_client *client; + struct regmap *regmap; + + struct clk *clk; + struct gpio_desc *reset; + struct regulator_bulk_data supplies[3]; + struct v4l2_fwnode_endpoint bus_cfg; + + struct { + unsigned int m; + unsigned int n; + unsigned int p; + } pll; + + unsigned int pixrate; + bool streaming; + + /* Pixel Array */ + struct { + struct v4l2_subdev sd; + struct media_pad pad; + + struct v4l2_ctrl_handler hdl; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *gain; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; + } pa; + + /* Image Flow Processor */ + struct { + struct v4l2_subdev sd; + struct media_pad pads[2]; + + struct v4l2_ctrl_handler hdl; + unsigned int frame_rate; + + struct v4l2_ctrl *tpg[4]; + } ifp; +}; + +/* ----------------------------------------------------------------------------- + * Formats + */ + +static const struct mt9m114_format_info mt9m114_format_infos[] = { + { + /* + * The first two entries are used as defaults, for parallel and + * CSI-2 buses respectively. Keep them in that order. + */ + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .flags = MT9M114_FMT_FLAG_PARALLEL, + .output_format = MT9M114_CAM_OUTPUT_FORMAT_FORMAT_YUV, + }, { + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .flags = MT9M114_FMT_FLAG_CSI2, + .output_format = MT9M114_CAM_OUTPUT_FORMAT_FORMAT_YUV, + }, { + .code = MEDIA_BUS_FMT_YUYV8_2X8, + .flags = MT9M114_FMT_FLAG_PARALLEL, + .output_format = MT9M114_CAM_OUTPUT_FORMAT_FORMAT_YUV + | MT9M114_CAM_OUTPUT_FORMAT_SWAP_BYTES, + }, { + .code = MEDIA_BUS_FMT_YUYV8_1X16, + .flags = MT9M114_FMT_FLAG_CSI2, + .output_format = MT9M114_CAM_OUTPUT_FORMAT_FORMAT_YUV + | MT9M114_CAM_OUTPUT_FORMAT_SWAP_BYTES, + }, { + .code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .flags = MT9M114_FMT_FLAG_PARALLEL, + .output_format = MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_565RGB + | MT9M114_CAM_OUTPUT_FORMAT_FORMAT_RGB + | MT9M114_CAM_OUTPUT_FORMAT_SWAP_BYTES, + }, { + .code = MEDIA_BUS_FMT_RGB565_2X8_BE, + .flags = MT9M114_FMT_FLAG_PARALLEL, + .output_format = MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_565RGB + | MT9M114_CAM_OUTPUT_FORMAT_FORMAT_RGB, + }, { + .code = MEDIA_BUS_FMT_RGB565_1X16, + .flags = MT9M114_FMT_FLAG_CSI2, + .output_format = MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_565RGB + | MT9M114_CAM_OUTPUT_FORMAT_FORMAT_RGB, + }, { + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .output_format = MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_PROCESSED8 + | MT9M114_CAM_OUTPUT_FORMAT_FORMAT_BAYER, + .flags = MT9M114_FMT_FLAG_PARALLEL | MT9M114_FMT_FLAG_CSI2, + }, { + /* Keep the format compatible with the IFP sink pad last. */ + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .output_format = MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_RAWR10 + | MT9M114_CAM_OUTPUT_FORMAT_FORMAT_BAYER, + .flags = MT9M114_FMT_FLAG_PARALLEL | MT9M114_FMT_FLAG_CSI2, + } +}; + +static const struct mt9m114_format_info * +mt9m114_default_format_info(struct mt9m114 *sensor) +{ + if (sensor->bus_cfg.bus_type == V4L2_MBUS_CSI2_DPHY) + return &mt9m114_format_infos[1]; + else + return &mt9m114_format_infos[0]; +} + +static const struct mt9m114_format_info * +mt9m114_format_info(struct mt9m114 *sensor, unsigned int pad, u32 code) +{ + const unsigned int num_formats = ARRAY_SIZE(mt9m114_format_infos); + unsigned int flag; + unsigned int i; + + switch (pad) { + case 0: + return &mt9m114_format_infos[num_formats - 1]; + + case 1: + if (sensor->bus_cfg.bus_type == V4L2_MBUS_CSI2_DPHY) + flag = MT9M114_FMT_FLAG_CSI2; + else + flag = MT9M114_FMT_FLAG_PARALLEL; + + for (i = 0; i < num_formats; ++i) { + const struct mt9m114_format_info *info = + &mt9m114_format_infos[i]; + + if (info->code == code && info->flags & flag) + return info; + } + + return mt9m114_default_format_info(sensor); + + default: + return NULL; + } +} + +/* ----------------------------------------------------------------------------- + * Initialization + */ + +static const struct cci_reg_sequence mt9m114_init[] = { + { MT9M114_RESET_REGISTER, MT9M114_RESET_REGISTER_MASK_BAD | + MT9M114_RESET_REGISTER_LOCK_REG | + 0x0010 }, + + /* Sensor optimization */ + { CCI_REG16(0x316a), 0x8270 }, + { CCI_REG16(0x316c), 0x8270 }, + { CCI_REG16(0x3ed0), 0x2305 }, + { CCI_REG16(0x3ed2), 0x77cf }, + { CCI_REG16(0x316e), 0x8202 }, + { CCI_REG16(0x3180), 0x87ff }, + { CCI_REG16(0x30d4), 0x6080 }, + { CCI_REG16(0xa802), 0x0008 }, + + { CCI_REG16(0x3e14), 0xff39 }, + + /* APGA */ + { MT9M114_CAM_PGA_PGA_CONTROL, 0x0000 }, + + /* Automatic White balance */ + { MT9M114_CAM_AWB_CCM_L(0), 0x0267 }, + { MT9M114_CAM_AWB_CCM_L(1), 0xff1a }, + { MT9M114_CAM_AWB_CCM_L(2), 0xffb3 }, + { MT9M114_CAM_AWB_CCM_L(3), 0xff80 }, + { MT9M114_CAM_AWB_CCM_L(4), 0x0166 }, + { MT9M114_CAM_AWB_CCM_L(5), 0x0003 }, + { MT9M114_CAM_AWB_CCM_L(6), 0xff9a }, + { MT9M114_CAM_AWB_CCM_L(7), 0xfeb4 }, + { MT9M114_CAM_AWB_CCM_L(8), 0x024d }, + { MT9M114_CAM_AWB_CCM_M(0), 0x01bf }, + { MT9M114_CAM_AWB_CCM_M(1), 0xff01 }, + { MT9M114_CAM_AWB_CCM_M(2), 0xfff3 }, + { MT9M114_CAM_AWB_CCM_M(3), 0xff75 }, + { MT9M114_CAM_AWB_CCM_M(4), 0x0198 }, + { MT9M114_CAM_AWB_CCM_M(5), 0xfffd }, + { MT9M114_CAM_AWB_CCM_M(6), 0xff9a }, + { MT9M114_CAM_AWB_CCM_M(7), 0xfee7 }, + { MT9M114_CAM_AWB_CCM_M(8), 0x02a8 }, + { MT9M114_CAM_AWB_CCM_R(0), 0x01d9 }, + { MT9M114_CAM_AWB_CCM_R(1), 0xff26 }, + { MT9M114_CAM_AWB_CCM_R(2), 0xfff3 }, + { MT9M114_CAM_AWB_CCM_R(3), 0xffb3 }, + { MT9M114_CAM_AWB_CCM_R(4), 0x0132 }, + { MT9M114_CAM_AWB_CCM_R(5), 0xffe8 }, + { MT9M114_CAM_AWB_CCM_R(6), 0xffda }, + { MT9M114_CAM_AWB_CCM_R(7), 0xfecd }, + { MT9M114_CAM_AWB_CCM_R(8), 0x02c2 }, + { MT9M114_CAM_AWB_CCM_L_RG_GAIN, 0x0075 }, + { MT9M114_CAM_AWB_CCM_L_BG_GAIN, 0x011c }, + { MT9M114_CAM_AWB_CCM_M_RG_GAIN, 0x009a }, + { MT9M114_CAM_AWB_CCM_M_BG_GAIN, 0x0105 }, + { MT9M114_CAM_AWB_CCM_R_RG_GAIN, 0x00a4 }, + { MT9M114_CAM_AWB_CCM_R_BG_GAIN, 0x00ac }, + { MT9M114_CAM_AWB_CCM_L_CTEMP, 0x0a8c }, + { MT9M114_CAM_AWB_CCM_M_CTEMP, 0x0f0a }, + { MT9M114_CAM_AWB_CCM_R_CTEMP, 0x1964 }, + { MT9M114_CAM_AWB_AWB_XSHIFT_PRE_ADJ, 51 }, + { MT9M114_CAM_AWB_AWB_YSHIFT_PRE_ADJ, 60 }, + { MT9M114_CAM_AWB_AWB_XSCALE, 3 }, + { MT9M114_CAM_AWB_AWB_YSCALE, 2 }, + { MT9M114_CAM_AWB_AWB_WEIGHTS(0), 0x0000 }, + { MT9M114_CAM_AWB_AWB_WEIGHTS(1), 0x0000 }, + { MT9M114_CAM_AWB_AWB_WEIGHTS(2), 0x0000 }, + { MT9M114_CAM_AWB_AWB_WEIGHTS(3), 0xe724 }, + { MT9M114_CAM_AWB_AWB_WEIGHTS(4), 0x1583 }, + { MT9M114_CAM_AWB_AWB_WEIGHTS(5), 0x2045 }, + { MT9M114_CAM_AWB_AWB_WEIGHTS(6), 0x03ff }, + { MT9M114_CAM_AWB_AWB_WEIGHTS(7), 0x007c }, + { MT9M114_CAM_AWB_K_R_L, 0x80 }, + { MT9M114_CAM_AWB_K_G_L, 0x80 }, + { MT9M114_CAM_AWB_K_B_L, 0x80 }, + { MT9M114_CAM_AWB_K_R_R, 0x88 }, + { MT9M114_CAM_AWB_K_G_R, 0x80 }, + { MT9M114_CAM_AWB_K_B_R, 0x80 }, + + /* Low-Light Image Enhancements */ + { MT9M114_CAM_LL_START_BRIGHTNESS, 0x0020 }, + { MT9M114_CAM_LL_STOP_BRIGHTNESS, 0x009a }, + { MT9M114_CAM_LL_START_GAIN_METRIC, 0x0070 }, + { MT9M114_CAM_LL_STOP_GAIN_METRIC, 0x00f3 }, + { MT9M114_CAM_LL_START_CONTRAST_LUMA_PERCENTAGE, 0x20 }, + { MT9M114_CAM_LL_STOP_CONTRAST_LUMA_PERCENTAGE, 0x9a }, + { MT9M114_CAM_LL_START_SATURATION, 0x80 }, + { MT9M114_CAM_LL_END_SATURATION, 0x4b }, + { MT9M114_CAM_LL_START_DESATURATION, 0x00 }, + { MT9M114_CAM_LL_END_DESATURATION, 0xff }, + { MT9M114_CAM_LL_START_DEMOSAICING, 0x3c }, + { MT9M114_CAM_LL_START_AP_GAIN, 0x02 }, + { MT9M114_CAM_LL_START_AP_THRESH, 0x06 }, + { MT9M114_CAM_LL_STOP_DEMOSAICING, 0x64 }, + { MT9M114_CAM_LL_STOP_AP_GAIN, 0x01 }, + { MT9M114_CAM_LL_STOP_AP_THRESH, 0x0c }, + { MT9M114_CAM_LL_START_NR_RED, 0x3c }, + { MT9M114_CAM_LL_START_NR_GREEN, 0x3c }, + { MT9M114_CAM_LL_START_NR_BLUE, 0x3c }, + { MT9M114_CAM_LL_START_NR_THRESH, 0x0f }, + { MT9M114_CAM_LL_STOP_NR_RED, 0x64 }, + { MT9M114_CAM_LL_STOP_NR_GREEN, 0x64 }, + { MT9M114_CAM_LL_STOP_NR_BLUE, 0x64 }, + { MT9M114_CAM_LL_STOP_NR_THRESH, 0x32 }, + { MT9M114_CAM_LL_START_CONTRAST_BM, 0x0020 }, + { MT9M114_CAM_LL_STOP_CONTRAST_BM, 0x009a }, + { MT9M114_CAM_LL_GAMMA, 0x00dc }, + { MT9M114_CAM_LL_START_CONTRAST_GRADIENT, 0x38 }, + { MT9M114_CAM_LL_STOP_CONTRAST_GRADIENT, 0x30 }, + { MT9M114_CAM_LL_START_CONTRAST_LUMA_PERCENTAGE, 0x50 }, + { MT9M114_CAM_LL_STOP_CONTRAST_LUMA_PERCENTAGE, 0x19 }, + { MT9M114_CAM_LL_START_FADE_TO_BLACK_LUMA, 0x0230 }, + { MT9M114_CAM_LL_STOP_FADE_TO_BLACK_LUMA, 0x0010 }, + { MT9M114_CAM_LL_CLUSTER_DC_TH_BM, 0x01cd }, + { MT9M114_CAM_LL_CLUSTER_DC_GATE_PERCENTAGE, 0x05 }, + { MT9M114_CAM_LL_SUMMING_SENSITIVITY_FACTOR, 0x40 }, + + /* Auto-Exposure */ + { MT9M114_CAM_AET_TARGET_AVERAGE_LUMA_DARK, 0x1b }, + { MT9M114_CAM_AET_AEMODE, 0x00 }, + { MT9M114_CAM_AET_TARGET_GAIN, 0x0080 }, + { MT9M114_CAM_AET_AE_MAX_VIRT_AGAIN, 0x0100 }, + { MT9M114_CAM_AET_BLACK_CLIPPING_TARGET, 0x005a }, + + { MT9M114_CCM_DELTA_GAIN, 0x05 }, + { MT9M114_AE_TRACK_AE_TRACKING_DAMPENING_SPEED, 0x20 }, + + /* Pixel array timings and integration time */ + { MT9M114_CAM_SENSOR_CFG_ROW_SPEED, 1 }, + { MT9M114_CAM_SENSOR_CFG_FINE_INTEG_TIME_MIN, 219 }, + { MT9M114_CAM_SENSOR_CFG_FINE_INTEG_TIME_MAX, 1459 }, + { MT9M114_CAM_SENSOR_CFG_FINE_CORRECTION, 96 }, + { MT9M114_CAM_SENSOR_CFG_REG_0_DATA, 32 }, + + /* Miscellaneous settings */ + { MT9M114_PAD_SLEW, 0x0777 }, +}; + +/* ----------------------------------------------------------------------------- + * Hardware Configuration + */ + +/* Wait for a command to complete. */ +static int mt9m114_poll_command(struct mt9m114 *sensor, u32 command) +{ + unsigned int i; + u64 value; + int ret; + + for (i = 0; i < 100; ++i) { + ret = cci_read(sensor->regmap, MT9M114_COMMAND_REGISTER, &value, + NULL); + if (ret < 0) + return ret; + + if (!(value & command)) + break; + + usleep_range(5000, 6000); + } + + if (value & command) { + dev_err(&sensor->client->dev, "Command %u completion timeout\n", + command); + return -ETIMEDOUT; + } + + if (!(value & MT9M114_COMMAND_REGISTER_OK)) { + dev_err(&sensor->client->dev, "Command %u failed\n", command); + return -EIO; + } + + return 0; +} + +/* Wait for a state to be entered. */ +static int mt9m114_poll_state(struct mt9m114 *sensor, u32 state) +{ + unsigned int i; + u64 value; + int ret; + + for (i = 0; i < 100; ++i) { + ret = cci_read(sensor->regmap, MT9M114_SYSMGR_CURRENT_STATE, + &value, NULL); + if (ret < 0) + return ret; + + if (value == state) + return 0; + + usleep_range(1000, 1500); + } + + dev_err(&sensor->client->dev, "Timeout waiting for state 0x%02x\n", + state); + return -ETIMEDOUT; +} + +static int mt9m114_set_state(struct mt9m114 *sensor, u8 next_state) +{ + int ret = 0; + + /* Set the next desired state and start the state transition. */ + cci_write(sensor->regmap, MT9M114_SYSMGR_NEXT_STATE, next_state, &ret); + cci_write(sensor->regmap, MT9M114_COMMAND_REGISTER, + MT9M114_COMMAND_REGISTER_OK | + MT9M114_COMMAND_REGISTER_SET_STATE, &ret); + if (ret < 0) + return ret; + + /* Wait for the state transition to complete. */ + ret = mt9m114_poll_command(sensor, MT9M114_COMMAND_REGISTER_SET_STATE); + if (ret < 0) + return ret; + + return 0; +} + +static int mt9m114_initialize(struct mt9m114 *sensor) +{ + u32 value; + int ret; + + ret = cci_multi_reg_write(sensor->regmap, mt9m114_init, + ARRAY_SIZE(mt9m114_init), NULL); + if (ret < 0) { + dev_err(&sensor->client->dev, + "Failed to initialize the sensor\n"); + return ret; + } + + /* Configure the PLL. */ + cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_ENABLE, + MT9M114_CAM_SYSCTL_PLL_ENABLE_VALUE, &ret); + cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_DIVIDER_M_N, + MT9M114_CAM_SYSCTL_PLL_DIVIDER_VALUE(sensor->pll.m, + sensor->pll.n), + &ret); + cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_DIVIDER_P, + MT9M114_CAM_SYSCTL_PLL_DIVIDER_P_VALUE(sensor->pll.p), &ret); + cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_PIXCLK, + sensor->pixrate, &ret); + + /* Configure the output mode. */ + if (sensor->bus_cfg.bus_type == V4L2_MBUS_CSI2_DPHY) { + value = MT9M114_CAM_PORT_PORT_SELECT_MIPI + | MT9M114_CAM_PORT_CHAN_NUM(0) + | 0x8000; + if (!(sensor->bus_cfg.bus.mipi_csi2.flags & + V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK)) + value |= MT9M114_CAM_PORT_CONT_MIPI_CLK; + } else { + value = MT9M114_CAM_PORT_PORT_SELECT_PARALLEL + | 0x8000; + } + cci_write(sensor->regmap, MT9M114_CAM_PORT_OUTPUT_CONTROL, value, &ret); + if (ret < 0) + return ret; + + ret = mt9m114_set_state(sensor, MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE); + if (ret < 0) + return ret; + + ret = mt9m114_set_state(sensor, MT9M114_SYS_STATE_ENTER_SUSPEND); + if (ret < 0) + return ret; + + return 0; +} + +static int mt9m114_configure(struct mt9m114 *sensor, + struct v4l2_subdev_state *pa_state, + struct v4l2_subdev_state *ifp_state) +{ + const struct v4l2_mbus_framefmt *pa_format; + const struct v4l2_rect *pa_crop; + const struct mt9m114_format_info *ifp_info; + const struct v4l2_mbus_framefmt *ifp_format; + const struct v4l2_rect *ifp_crop; + const struct v4l2_rect *ifp_compose; + unsigned int hratio, vratio; + u64 output_format; + u64 read_mode; + int ret = 0; + + pa_format = v4l2_subdev_get_pad_format(&sensor->pa.sd, pa_state, 0); + pa_crop = v4l2_subdev_get_pad_crop(&sensor->pa.sd, pa_state, 0); + + ifp_format = v4l2_subdev_get_pad_format(&sensor->ifp.sd, ifp_state, 1); + ifp_info = mt9m114_format_info(sensor, 1, ifp_format->code); + ifp_crop = v4l2_subdev_get_pad_crop(&sensor->ifp.sd, ifp_state, 0); + ifp_compose = v4l2_subdev_get_pad_compose(&sensor->ifp.sd, ifp_state, 0); + + ret = cci_read(sensor->regmap, MT9M114_CAM_SENSOR_CONTROL_READ_MODE, + &read_mode, NULL); + if (ret < 0) + return ret; + + ret = cci_read(sensor->regmap, MT9M114_CAM_OUTPUT_FORMAT, + &output_format, NULL); + if (ret < 0) + return ret; + + hratio = pa_crop->width / pa_format->width; + vratio = pa_crop->height / pa_format->height; + + /* + * Pixel array crop and binning. The CAM_SENSOR_CFG_CPIPE_LAST_ROW + * register isn't clearly documented, but is always set to the number + * of active rows minus 4 divided by the vertical binning factor in all + * example sensor modes. + */ + cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_X_ADDR_START, + pa_crop->left, &ret); + cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_Y_ADDR_START, + pa_crop->top, &ret); + cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_X_ADDR_END, + pa_crop->width + pa_crop->left - 1, &ret); + cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_Y_ADDR_END, + pa_crop->height + pa_crop->top - 1, &ret); + cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_CPIPE_LAST_ROW, + (pa_crop->height - 4) / vratio - 1, &ret); + + read_mode &= ~(MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_MASK | + MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_MASK); + + if (hratio > 1) + read_mode |= MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_SUMMING; + if (vratio > 1) + read_mode |= MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_SUMMING; + + cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CONTROL_READ_MODE, + read_mode, &ret); + + /* + * Color pipeline (IFP) cropping and scaling. Subtract 4 from the left + * and top coordinates to compensate for the lines and columns removed + * by demosaicing that are taken into account in the crop rectangle but + * not in the hardware. + */ + cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_XOFFSET, + ifp_crop->left - 4, &ret); + cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_YOFFSET, + ifp_crop->top - 4, &ret); + cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_WIDTH, + ifp_crop->width, &ret); + cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_HEIGHT, + ifp_crop->height, &ret); + + cci_write(sensor->regmap, MT9M114_CAM_OUTPUT_WIDTH, + ifp_compose->width, &ret); + cci_write(sensor->regmap, MT9M114_CAM_OUTPUT_HEIGHT, + ifp_compose->height, &ret); + + /* AWB and AE windows, use the full frame. */ + cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XSTART, + 0, &ret); + cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YSTART, + 0, &ret); + cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XEND, + ifp_compose->width - 1, &ret); + cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YEND, + ifp_compose->height - 1, &ret); + + cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XSTART, + 0, &ret); + cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YSTART, + 0, &ret); + cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XEND, + ifp_compose->width / 5 - 1, &ret); + cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YEND, + ifp_compose->height / 5 - 1, &ret); + + cci_write(sensor->regmap, MT9M114_CAM_CROP_CROPMODE, + MT9M114_CAM_CROP_MODE_AWB_AUTO_CROP_EN | + MT9M114_CAM_CROP_MODE_AE_AUTO_CROP_EN, &ret); + + /* Set the media bus code. */ + output_format &= ~(MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_MASK | + MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_MASK | + MT9M114_CAM_OUTPUT_FORMAT_FORMAT_MASK | + MT9M114_CAM_OUTPUT_FORMAT_SWAP_BYTES | + MT9M114_CAM_OUTPUT_FORMAT_SWAP_RED_BLUE); + output_format |= ifp_info->output_format; + + cci_write(sensor->regmap, MT9M114_CAM_OUTPUT_FORMAT, + output_format, &ret); + + return ret; +} + +static int mt9m114_set_frame_rate(struct mt9m114 *sensor) +{ + u16 frame_rate = sensor->ifp.frame_rate << 8; + int ret = 0; + + cci_write(sensor->regmap, MT9M114_CAM_AET_MIN_FRAME_RATE, + frame_rate, &ret); + cci_write(sensor->regmap, MT9M114_CAM_AET_MAX_FRAME_RATE, + frame_rate, &ret); + + return ret; +} + +static int mt9m114_start_streaming(struct mt9m114 *sensor, + struct v4l2_subdev_state *pa_state, + struct v4l2_subdev_state *ifp_state) +{ + int ret; + + ret = pm_runtime_resume_and_get(&sensor->client->dev); + if (ret) + return ret; + + ret = mt9m114_configure(sensor, pa_state, ifp_state); + if (ret) + goto error; + + ret = mt9m114_set_frame_rate(sensor); + if (ret) + goto error; + + ret = __v4l2_ctrl_handler_setup(&sensor->pa.hdl); + if (ret) + goto error; + + ret = __v4l2_ctrl_handler_setup(&sensor->ifp.hdl); + if (ret) + goto error; + + /* + * The Change-Config state is transient and moves to the streaming + * state automatically. + */ + ret = mt9m114_set_state(sensor, MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE); + if (ret) + goto error; + + sensor->streaming = true; + + return 0; + +error: + pm_runtime_mark_last_busy(&sensor->client->dev); + pm_runtime_put_autosuspend(&sensor->client->dev); + + return ret; +} + +static int mt9m114_stop_streaming(struct mt9m114 *sensor) +{ + int ret; + + sensor->streaming = false; + + ret = mt9m114_set_state(sensor, MT9M114_SYS_STATE_ENTER_SUSPEND); + + pm_runtime_mark_last_busy(&sensor->client->dev); + pm_runtime_put_autosuspend(&sensor->client->dev); + + return ret; +} + +/* ----------------------------------------------------------------------------- + * Common Subdev Operations + */ + +static const struct media_entity_operations mt9m114_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +/* ----------------------------------------------------------------------------- + * Pixel Array Control Operations + */ + +static inline struct mt9m114 *pa_ctrl_to_mt9m114(struct v4l2_ctrl *ctrl) +{ + return container_of(ctrl->handler, struct mt9m114, pa.hdl); +} + +static int mt9m114_pa_g_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mt9m114 *sensor = pa_ctrl_to_mt9m114(ctrl); + u64 value; + int ret; + + if (!pm_runtime_get_if_in_use(&sensor->client->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + ret = cci_read(sensor->regmap, + MT9M114_CAM_SENSOR_CONTROL_COARSE_INTEGRATION_TIME, + &value, NULL); + if (ret) + break; + + ctrl->val = value; + break; + + case V4L2_CID_ANALOGUE_GAIN: + ret = cci_read(sensor->regmap, + MT9M114_CAM_SENSOR_CONTROL_ANALOG_GAIN, + &value, NULL); + if (ret) + break; + + ctrl->val = value; + break; + + default: + ret = -EINVAL; + break; + } + + pm_runtime_mark_last_busy(&sensor->client->dev); + pm_runtime_put_autosuspend(&sensor->client->dev); + + return ret; +} + +static int mt9m114_pa_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mt9m114 *sensor = pa_ctrl_to_mt9m114(ctrl); + const struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; + int ret = 0; + u64 mask; + + /* V4L2 controls values are applied only when power is up. */ + if (!pm_runtime_get_if_in_use(&sensor->client->dev)) + return 0; + + state = v4l2_subdev_get_locked_active_state(&sensor->pa.sd); + format = v4l2_subdev_get_pad_format(&sensor->pa.sd, state, 0); + + switch (ctrl->id) { + case V4L2_CID_HBLANK: + cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_LINE_LENGTH_PCK, + ctrl->val + format->width, &ret); + break; + + case V4L2_CID_VBLANK: + cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_FRAME_LENGTH_LINES, + ctrl->val + format->height, &ret); + break; + + case V4L2_CID_EXPOSURE: + cci_write(sensor->regmap, + MT9M114_CAM_SENSOR_CONTROL_COARSE_INTEGRATION_TIME, + ctrl->val, &ret); + break; + + case V4L2_CID_ANALOGUE_GAIN: + /* + * The CAM_SENSOR_CONTROL_ANALOG_GAIN contains linear analog + * gain values that are mapped to the GLOBAL_GAIN register + * values by the sensor firmware. + */ + cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CONTROL_ANALOG_GAIN, + ctrl->val, &ret); + break; + + case V4L2_CID_HFLIP: + mask = MT9M114_CAM_SENSOR_CONTROL_HORZ_MIRROR_EN; + ret = cci_update_bits(sensor->regmap, + MT9M114_CAM_SENSOR_CONTROL_READ_MODE, + mask, ctrl->val ? mask : 0, NULL); + break; + + case V4L2_CID_VFLIP: + mask = MT9M114_CAM_SENSOR_CONTROL_VERT_FLIP_EN; + ret = cci_update_bits(sensor->regmap, + MT9M114_CAM_SENSOR_CONTROL_READ_MODE, + mask, ctrl->val ? mask : 0, NULL); + break; + + default: + ret = -EINVAL; + break; + } + + pm_runtime_mark_last_busy(&sensor->client->dev); + pm_runtime_put_autosuspend(&sensor->client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops mt9m114_pa_ctrl_ops = { + .g_volatile_ctrl = mt9m114_pa_g_ctrl, + .s_ctrl = mt9m114_pa_s_ctrl, +}; + +static void mt9m114_pa_ctrl_update_exposure(struct mt9m114 *sensor, bool manual) +{ + /* + * Update the volatile flag on the manual exposure and gain controls. + * If the controls have switched to manual, read their current value + * from the hardware to ensure that control read and write operations + * will behave correctly + */ + if (manual) { + mt9m114_pa_g_ctrl(sensor->pa.exposure); + sensor->pa.exposure->cur.val = sensor->pa.exposure->val; + sensor->pa.exposure->flags &= ~V4L2_CTRL_FLAG_VOLATILE; + + mt9m114_pa_g_ctrl(sensor->pa.gain); + sensor->pa.gain->cur.val = sensor->pa.gain->val; + sensor->pa.gain->flags &= ~V4L2_CTRL_FLAG_VOLATILE; + } else { + sensor->pa.exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; + sensor->pa.gain->flags |= V4L2_CTRL_FLAG_VOLATILE; + } +} + +static void mt9m114_pa_ctrl_update_blanking(struct mt9m114 *sensor, + const struct v4l2_mbus_framefmt *format) +{ + unsigned int max_blank; + + /* Update the blanking controls ranges based on the output size. */ + max_blank = MT9M114_CAM_SENSOR_CFG_LINE_LENGTH_PCK_MAX + - format->width; + __v4l2_ctrl_modify_range(sensor->pa.hblank, MT9M114_MIN_HBLANK, + max_blank, 1, MT9M114_DEF_HBLANK); + + max_blank = MT9M114_CAM_SENSOR_CFG_FRAME_LENGTH_LINES_MAX + - format->height; + __v4l2_ctrl_modify_range(sensor->pa.vblank, MT9M114_MIN_VBLANK, + max_blank, 1, MT9M114_DEF_VBLANK); +} + +/* ----------------------------------------------------------------------------- + * Pixel Array Subdev Operations + */ + +static inline struct mt9m114 *pa_to_mt9m114(struct v4l2_subdev *sd) +{ + return container_of(sd, struct mt9m114, pa.sd); +} + +static int mt9m114_pa_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + + crop = v4l2_subdev_get_pad_crop(sd, state, 0); + + crop->left = 0; + crop->top = 0; + crop->width = MT9M114_PIXEL_ARRAY_WIDTH; + crop->height = MT9M114_PIXEL_ARRAY_HEIGHT; + + format = v4l2_subdev_get_pad_format(sd, state, 0); + + format->width = MT9M114_PIXEL_ARRAY_WIDTH; + format->height = MT9M114_PIXEL_ARRAY_HEIGHT; + format->code = MEDIA_BUS_FMT_SGRBG10_1X10; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_RAW; + format->ycbcr_enc = V4L2_YCBCR_ENC_601; + format->quantization = V4L2_QUANTIZATION_FULL_RANGE; + format->xfer_func = V4L2_XFER_FUNC_NONE; + + return 0; +} + +static int mt9m114_pa_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index > 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SGRBG10_1X10; + + return 0; +} + +static int mt9m114_pa_enum_framesizes(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index > 1) + return -EINVAL; + + if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) + return -EINVAL; + + /* Report binning capability through frame size enumeration. */ + fse->min_width = MT9M114_PIXEL_ARRAY_WIDTH / (fse->index + 1); + fse->max_width = MT9M114_PIXEL_ARRAY_WIDTH / (fse->index + 1); + fse->min_height = MT9M114_PIXEL_ARRAY_HEIGHT / (fse->index + 1); + fse->max_height = MT9M114_PIXEL_ARRAY_HEIGHT / (fse->index + 1); + + return 0; +} + +static int mt9m114_pa_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct mt9m114 *sensor = pa_to_mt9m114(sd); + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + unsigned int hscale; + unsigned int vscale; + + crop = v4l2_subdev_get_pad_crop(sd, state, fmt->pad); + format = v4l2_subdev_get_pad_format(sd, state, fmt->pad); + + /* The sensor can bin horizontally and vertically. */ + hscale = DIV_ROUND_CLOSEST(crop->width, fmt->format.width ? : 1); + vscale = DIV_ROUND_CLOSEST(crop->height, fmt->format.height ? : 1); + format->width = crop->width / clamp(hscale, 1U, 2U); + format->height = crop->height / clamp(vscale, 1U, 2U); + + fmt->format = *format; + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) + mt9m114_pa_ctrl_update_blanking(sensor, format); + + return 0; +} + +static int mt9m114_pa_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + sel->r = *v4l2_subdev_get_pad_crop(sd, state, sel->pad); + return 0; + + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = MT9M114_PIXEL_ARRAY_WIDTH; + sel->r.height = MT9M114_PIXEL_ARRAY_HEIGHT; + return 0; + + default: + return -EINVAL; + } +} + +static int mt9m114_pa_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct mt9m114 *sensor = pa_to_mt9m114(sd); + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + crop = v4l2_subdev_get_pad_crop(sd, state, sel->pad); + format = v4l2_subdev_get_pad_format(sd, state, sel->pad); + + /* + * Clamp the crop rectangle. The vertical coordinates must be even, and + * the horizontal coordinates must be a multiple of 4. + * + * FIXME: The horizontal coordinates must be a multiple of 8 when + * binning, but binning is configured after setting the selection, so + * we can't know tell here if it will be used. + */ + crop->left = ALIGN(sel->r.left, 4); + crop->top = ALIGN(sel->r.top, 2); + crop->width = clamp_t(unsigned int, ALIGN(sel->r.width, 4), + MT9M114_PIXEL_ARRAY_MIN_OUTPUT_WIDTH, + MT9M114_PIXEL_ARRAY_WIDTH - crop->left); + crop->height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), + MT9M114_PIXEL_ARRAY_MIN_OUTPUT_HEIGHT, + MT9M114_PIXEL_ARRAY_HEIGHT - crop->top); + + sel->r = *crop; + + /* Reset the format. */ + format->width = crop->width; + format->height = crop->height; + + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) + mt9m114_pa_ctrl_update_blanking(sensor, format); + + return 0; +} + +static const struct v4l2_subdev_pad_ops mt9m114_pa_pad_ops = { + .init_cfg = mt9m114_pa_init_cfg, + .enum_mbus_code = mt9m114_pa_enum_mbus_code, + .enum_frame_size = mt9m114_pa_enum_framesizes, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = mt9m114_pa_set_fmt, + .get_selection = mt9m114_pa_get_selection, + .set_selection = mt9m114_pa_set_selection, +}; + +static const struct v4l2_subdev_ops mt9m114_pa_ops = { + .pad = &mt9m114_pa_pad_ops, +}; + +static int mt9m114_pa_init(struct mt9m114 *sensor) +{ + struct v4l2_ctrl_handler *hdl = &sensor->pa.hdl; + struct v4l2_subdev *sd = &sensor->pa.sd; + struct media_pad *pads = &sensor->pa.pad; + const struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; + unsigned int max_exposure; + int ret; + + /* Initialize the subdev. */ + v4l2_subdev_init(sd, &mt9m114_pa_ops); + v4l2_i2c_subdev_set_name(sd, sensor->client, NULL, " pixel array"); + + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->owner = THIS_MODULE; + sd->dev = &sensor->client->dev; + v4l2_set_subdevdata(sd, sensor->client); + + /* Initialize the media entity. */ + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + sd->entity.ops = &mt9m114_entity_ops; + pads[0].flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&sd->entity, 1, pads); + if (ret < 0) + return ret; + + /* Initialize the control handler. */ + v4l2_ctrl_handler_init(hdl, 7); + + /* The range of the HBLANK and VBLANK controls will be updated below. */ + sensor->pa.hblank = v4l2_ctrl_new_std(hdl, &mt9m114_pa_ctrl_ops, + V4L2_CID_HBLANK, + MT9M114_DEF_HBLANK, + MT9M114_DEF_HBLANK, 1, + MT9M114_DEF_HBLANK); + sensor->pa.vblank = v4l2_ctrl_new_std(hdl, &mt9m114_pa_ctrl_ops, + V4L2_CID_VBLANK, + MT9M114_DEF_VBLANK, + MT9M114_DEF_VBLANK, 1, + MT9M114_DEF_VBLANK); + + /* + * The maximum coarse integration time is the frame length in lines + * minus two. The default is taken directly from the datasheet, but + * makes little sense as auto-exposure is enabled by default. + */ + max_exposure = MT9M114_PIXEL_ARRAY_HEIGHT + MT9M114_MIN_VBLANK - 2; + sensor->pa.exposure = v4l2_ctrl_new_std(hdl, &mt9m114_pa_ctrl_ops, + V4L2_CID_EXPOSURE, 1, + max_exposure, 1, 16); + if (sensor->pa.exposure) + sensor->pa.exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; + + sensor->pa.gain = v4l2_ctrl_new_std(hdl, &mt9m114_pa_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, 1, + 511, 1, 32); + if (sensor->pa.gain) + sensor->pa.gain->flags |= V4L2_CTRL_FLAG_VOLATILE; + + v4l2_ctrl_new_std(hdl, &mt9m114_pa_ctrl_ops, + V4L2_CID_PIXEL_RATE, + sensor->pixrate, sensor->pixrate, 1, + sensor->pixrate); + + v4l2_ctrl_new_std(hdl, &mt9m114_pa_ctrl_ops, + V4L2_CID_HFLIP, + 0, 1, 1, 0); + v4l2_ctrl_new_std(hdl, &mt9m114_pa_ctrl_ops, + V4L2_CID_VFLIP, + 0, 1, 1, 0); + + if (hdl->error) { + ret = hdl->error; + goto error; + } + + sd->state_lock = hdl->lock; + + ret = v4l2_subdev_init_finalize(sd); + if (ret) + goto error; + + /* Update the range of the blanking controls based on the format. */ + state = v4l2_subdev_lock_and_get_active_state(sd); + format = v4l2_subdev_get_pad_format(sd, state, 0); + mt9m114_pa_ctrl_update_blanking(sensor, format); + v4l2_subdev_unlock_state(state); + + sd->ctrl_handler = hdl; + + return 0; + +error: + v4l2_ctrl_handler_free(&sensor->pa.hdl); + media_entity_cleanup(&sensor->pa.sd.entity); + return ret; +} + +static void mt9m114_pa_cleanup(struct mt9m114 *sensor) +{ + v4l2_ctrl_handler_free(&sensor->pa.hdl); + media_entity_cleanup(&sensor->pa.sd.entity); +} + +/* ----------------------------------------------------------------------------- + * Image Flow Processor Control Operations + */ + +static const char * const mt9m114_test_pattern_menu[] = { + "Disabled", + "Solid Color", + "100% Color Bars", + "Pseudo-Random", + "Fade-to-Gray Color Bars", + "Walking Ones 10-bit", + "Walking Ones 8-bit", +}; + +/* Keep in sync with mt9m114_test_pattern_menu */ +static const unsigned int mt9m114_test_pattern_value[] = { + MT9M114_CAM_MODE_TEST_PATTERN_SELECT_SOLID, + MT9M114_CAM_MODE_TEST_PATTERN_SELECT_SOLID_BARS, + MT9M114_CAM_MODE_TEST_PATTERN_SELECT_RANDOM, + MT9M114_CAM_MODE_TEST_PATTERN_SELECT_FADING_BARS, + MT9M114_CAM_MODE_TEST_PATTERN_SELECT_WALKING_1S_10B, + MT9M114_CAM_MODE_TEST_PATTERN_SELECT_WALKING_1S_8B, +}; + +static inline struct mt9m114 *ifp_ctrl_to_mt9m114(struct v4l2_ctrl *ctrl) +{ + return container_of(ctrl->handler, struct mt9m114, ifp.hdl); +} + +static int mt9m114_ifp_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mt9m114 *sensor = ifp_ctrl_to_mt9m114(ctrl); + u32 value; + int ret = 0; + + if (ctrl->id == V4L2_CID_EXPOSURE_AUTO) + mt9m114_pa_ctrl_update_exposure(sensor, + ctrl->val != V4L2_EXPOSURE_AUTO); + + /* V4L2 controls values are applied only when power is up. */ + if (!pm_runtime_get_if_in_use(&sensor->client->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_AUTO_WHITE_BALANCE: + /* Control both the AWB mode and the CCM algorithm. */ + if (ctrl->val) + value = MT9M114_CAM_AWB_MODE_AUTO + | MT9M114_CAM_AWB_MODE_EXCLUSIVE_AE; + else + value = 0; + + cci_write(sensor->regmap, MT9M114_CAM_AWB_AWBMODE, value, &ret); + + if (ctrl->val) + value = MT9M114_CCM_EXEC_CALC_CCM_MATRIX | 0x22; + else + value = 0; + + cci_write(sensor->regmap, MT9M114_CCM_ALGO, value, &ret); + break; + + case V4L2_CID_EXPOSURE_AUTO: + if (ctrl->val == V4L2_EXPOSURE_AUTO) + value = MT9M114_AE_TRACK_EXEC_AUTOMATIC_EXPOSURE + | 0x00fe; + else + value = 0; + + cci_write(sensor->regmap, MT9M114_AE_TRACK_ALGO, value, &ret); + if (ret) + break; + + break; + + case V4L2_CID_TEST_PATTERN: + case V4L2_CID_TEST_PATTERN_RED: + case V4L2_CID_TEST_PATTERN_GREENR: + case V4L2_CID_TEST_PATTERN_BLUE: { + unsigned int pattern = sensor->ifp.tpg[MT9M114_TPG_PATTERN]->val; + + if (pattern) { + cci_write(sensor->regmap, MT9M114_CAM_MODE_SELECT, + MT9M114_CAM_MODE_SELECT_TEST_PATTERN, &ret); + cci_write(sensor->regmap, + MT9M114_CAM_MODE_TEST_PATTERN_SELECT, + mt9m114_test_pattern_value[pattern - 1], &ret); + cci_write(sensor->regmap, + MT9M114_CAM_MODE_TEST_PATTERN_RED, + sensor->ifp.tpg[MT9M114_TPG_RED]->val, &ret); + cci_write(sensor->regmap, + MT9M114_CAM_MODE_TEST_PATTERN_GREEN, + sensor->ifp.tpg[MT9M114_TPG_GREEN]->val, &ret); + cci_write(sensor->regmap, + MT9M114_CAM_MODE_TEST_PATTERN_BLUE, + sensor->ifp.tpg[MT9M114_TPG_BLUE]->val, &ret); + } else { + cci_write(sensor->regmap, MT9M114_CAM_MODE_SELECT, + MT9M114_CAM_MODE_SELECT_NORMAL, &ret); + } + + /* + * A Config-Change needs to be issued for the change to take + * effect. If we're not streaming ignore this, the change will + * be applied when the stream is started. + */ + if (ret || !sensor->streaming) + break; + + ret = mt9m114_set_state(sensor, + MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE); + break; + } + + default: + ret = -EINVAL; + break; + } + + pm_runtime_mark_last_busy(&sensor->client->dev); + pm_runtime_put_autosuspend(&sensor->client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops mt9m114_ifp_ctrl_ops = { + .s_ctrl = mt9m114_ifp_s_ctrl, +}; + +/* ----------------------------------------------------------------------------- + * Image Flow Processor Subdev Operations + */ + +static inline struct mt9m114 *ifp_to_mt9m114(struct v4l2_subdev *sd) +{ + return container_of(sd, struct mt9m114, ifp.sd); +} + +static int mt9m114_ifp_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + struct v4l2_subdev_state *pa_state; + struct v4l2_subdev_state *ifp_state; + int ret; + + if (!enable) + return mt9m114_stop_streaming(sensor); + + ifp_state = v4l2_subdev_lock_and_get_active_state(&sensor->ifp.sd); + pa_state = v4l2_subdev_lock_and_get_active_state(&sensor->pa.sd); + + ret = mt9m114_start_streaming(sensor, pa_state, ifp_state); + + v4l2_subdev_unlock_state(pa_state); + v4l2_subdev_unlock_state(ifp_state); + + return ret; +} + +static int mt9m114_ifp_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct v4l2_fract *ival = &interval->interval; + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + + mutex_lock(sensor->ifp.hdl.lock); + + ival->numerator = 1; + ival->denominator = sensor->ifp.frame_rate; + + mutex_unlock(sensor->ifp.hdl.lock); + + return 0; +} + +static int mt9m114_ifp_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct v4l2_fract *ival = &interval->interval; + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + int ret = 0; + + mutex_lock(sensor->ifp.hdl.lock); + + if (ival->numerator != 0 && ival->denominator != 0) + sensor->ifp.frame_rate = min_t(unsigned int, + ival->denominator / ival->numerator, + MT9M114_MAX_FRAME_RATE); + else + sensor->ifp.frame_rate = MT9M114_MAX_FRAME_RATE; + + ival->numerator = 1; + ival->denominator = sensor->ifp.frame_rate; + + if (sensor->streaming) + ret = mt9m114_set_frame_rate(sensor); + + mutex_unlock(sensor->ifp.hdl.lock); + + return ret; +} + +static int mt9m114_ifp_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + struct v4l2_rect *compose; + + format = v4l2_subdev_get_pad_format(sd, state, 0); + + format->width = MT9M114_PIXEL_ARRAY_WIDTH; + format->height = MT9M114_PIXEL_ARRAY_HEIGHT; + format->code = MEDIA_BUS_FMT_SGRBG10_1X10; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_RAW; + format->ycbcr_enc = V4L2_YCBCR_ENC_601; + format->quantization = V4L2_QUANTIZATION_FULL_RANGE; + format->xfer_func = V4L2_XFER_FUNC_NONE; + + crop = v4l2_subdev_get_pad_crop(sd, state, 0); + + crop->left = 4; + crop->top = 4; + crop->width = format->width - 8; + crop->height = format->height - 8; + + compose = v4l2_subdev_get_pad_compose(sd, state, 0); + + compose->left = 0; + compose->top = 0; + compose->width = crop->width; + compose->height = crop->height; + + format = v4l2_subdev_get_pad_format(sd, state, 1); + + format->width = compose->width; + format->height = compose->height; + format->code = mt9m114_default_format_info(sensor)->code; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_SRGB; + format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + format->quantization = V4L2_QUANTIZATION_DEFAULT; + format->xfer_func = V4L2_XFER_FUNC_DEFAULT; + + return 0; +} + +static int mt9m114_ifp_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + const unsigned int num_formats = ARRAY_SIZE(mt9m114_format_infos); + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + unsigned int index = 0; + unsigned int flag; + unsigned int i; + + switch (code->pad) { + case 0: + if (code->index != 0) + return -EINVAL; + + code->code = mt9m114_format_infos[num_formats - 1].code; + return 0; + + case 1: + if (sensor->bus_cfg.bus_type == V4L2_MBUS_CSI2_DPHY) + flag = MT9M114_FMT_FLAG_CSI2; + else + flag = MT9M114_FMT_FLAG_PARALLEL; + + for (i = 0; i < num_formats; ++i) { + const struct mt9m114_format_info *info = + &mt9m114_format_infos[i]; + + if (info->flags & flag) { + if (index == code->index) { + code->code = info->code; + return 0; + } + + index++; + } + } + + return -EINVAL; + + default: + return -EINVAL; + } +} + +static int mt9m114_ifp_enum_framesizes(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + const struct mt9m114_format_info *info; + + if (fse->index > 0) + return -EINVAL; + + info = mt9m114_format_info(sensor, fse->pad, fse->code); + if (!info || info->code != fse->code) + return -EINVAL; + + if (fse->pad == 0) { + fse->min_width = MT9M114_PIXEL_ARRAY_MIN_OUTPUT_WIDTH; + fse->max_width = MT9M114_PIXEL_ARRAY_WIDTH; + fse->min_height = MT9M114_PIXEL_ARRAY_MIN_OUTPUT_HEIGHT; + fse->max_height = MT9M114_PIXEL_ARRAY_HEIGHT; + } else { + const struct v4l2_rect *crop; + + crop = v4l2_subdev_get_pad_crop(sd, state, 0); + + fse->max_width = crop->width; + fse->max_height = crop->height; + + fse->min_width = fse->max_width / 4; + fse->min_height = fse->max_height / 4; + } + + return 0; +} + +static int mt9m114_ifp_enum_frameintervals(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_interval_enum *fie) +{ + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + const struct mt9m114_format_info *info; + + if (fie->index > 0) + return -EINVAL; + + info = mt9m114_format_info(sensor, fie->pad, fie->code); + if (!info || info->code != fie->code) + return -EINVAL; + + fie->interval.numerator = 1; + fie->interval.denominator = MT9M114_MAX_FRAME_RATE; + + return 0; +} + +static int mt9m114_ifp_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + struct v4l2_mbus_framefmt *format; + + format = v4l2_subdev_get_pad_format(sd, state, fmt->pad); + + if (fmt->pad == 0) { + /* Only the size can be changed on the sink pad. */ + format->width = clamp(ALIGN(fmt->format.width, 8), + MT9M114_PIXEL_ARRAY_MIN_OUTPUT_WIDTH, + MT9M114_PIXEL_ARRAY_WIDTH); + format->height = clamp(ALIGN(fmt->format.height, 8), + MT9M114_PIXEL_ARRAY_MIN_OUTPUT_HEIGHT, + MT9M114_PIXEL_ARRAY_HEIGHT); + } else { + const struct mt9m114_format_info *info; + + /* Only the media bus code can be changed on the source pad. */ + info = mt9m114_format_info(sensor, 1, fmt->format.code); + + format->code = info->code; + + /* If the output format is RAW10, bypass the scaler. */ + if (format->code == MEDIA_BUS_FMT_SGRBG10_1X10) + *format = *v4l2_subdev_get_pad_format(sd, state, 0); + } + + fmt->format = *format; + + return 0; +} + +static int mt9m114_ifp_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + const struct v4l2_mbus_framefmt *format; + const struct v4l2_rect *crop; + int ret = 0; + + /* Crop and compose are only supported on the sink pad. */ + if (sel->pad != 0) + return -EINVAL; + + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + sel->r = *v4l2_subdev_get_pad_crop(sd, state, 0); + break; + + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + /* + * The crop default and bounds are equal to the sink + * format size minus 4 pixels on each side for demosaicing. + */ + format = v4l2_subdev_get_pad_format(sd, state, 0); + + sel->r.left = 4; + sel->r.top = 4; + sel->r.width = format->width - 8; + sel->r.height = format->height - 8; + break; + + case V4L2_SEL_TGT_COMPOSE: + sel->r = *v4l2_subdev_get_pad_compose(sd, state, 0); + break; + + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + /* + * The compose default and bounds sizes are equal to the sink + * crop rectangle size. + */ + crop = v4l2_subdev_get_pad_crop(sd, state, 0); + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = crop->width; + sel->r.height = crop->height; + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int mt9m114_ifp_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + struct v4l2_rect *compose; + + if (sel->target != V4L2_SEL_TGT_CROP && + sel->target != V4L2_SEL_TGT_COMPOSE) + return -EINVAL; + + /* Crop and compose are only supported on the sink pad. */ + if (sel->pad != 0) + return -EINVAL; + + format = v4l2_subdev_get_pad_format(sd, state, 0); + crop = v4l2_subdev_get_pad_crop(sd, state, 0); + compose = v4l2_subdev_get_pad_compose(sd, state, 0); + + if (sel->target == V4L2_SEL_TGT_CROP) { + /* + * Clamp the crop rectangle. Demosaicing removes 4 pixels on + * each side of the image. + */ + crop->left = clamp_t(unsigned int, ALIGN(sel->r.left, 2), 4, + format->width - 4 - + MT9M114_SCALER_CROPPED_INPUT_WIDTH); + crop->top = clamp_t(unsigned int, ALIGN(sel->r.top, 2), 4, + format->height - 4 - + MT9M114_SCALER_CROPPED_INPUT_HEIGHT); + crop->width = clamp_t(unsigned int, ALIGN(sel->r.width, 2), + MT9M114_SCALER_CROPPED_INPUT_WIDTH, + format->width - 4 - crop->left); + crop->height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), + MT9M114_SCALER_CROPPED_INPUT_HEIGHT, + format->height - 4 - crop->top); + + sel->r = *crop; + + /* Propagate to the compose rectangle. */ + compose->width = crop->width; + compose->height = crop->height; + } else { + /* + * Clamp the compose rectangle. The scaler can only downscale. + */ + compose->left = 0; + compose->top = 0; + compose->width = clamp_t(unsigned int, ALIGN(sel->r.width, 2), + MT9M114_SCALER_CROPPED_INPUT_WIDTH, + crop->width); + compose->height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), + MT9M114_SCALER_CROPPED_INPUT_HEIGHT, + crop->height); + + sel->r = *compose; + } + + /* Propagate the compose rectangle to the source format. */ + format = v4l2_subdev_get_pad_format(sd, state, 1); + format->width = compose->width; + format->height = compose->height; + + return 0; +} + +static void mt9m114_ifp_unregistered(struct v4l2_subdev *sd) +{ + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + + v4l2_device_unregister_subdev(&sensor->pa.sd); +} + +static int mt9m114_ifp_registered(struct v4l2_subdev *sd) +{ + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + int ret; + + ret = v4l2_device_register_subdev(sd->v4l2_dev, &sensor->pa.sd); + if (ret < 0) { + dev_err(&sensor->client->dev, + "Failed to register pixel array subdev\n"); + return ret; + } + + ret = media_create_pad_link(&sensor->pa.sd.entity, 0, + &sensor->ifp.sd.entity, 0, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret < 0) { + dev_err(&sensor->client->dev, + "Failed to link pixel array to ifp\n"); + v4l2_device_unregister_subdev(&sensor->pa.sd); + return ret; + } + + return 0; +} + +static const struct v4l2_subdev_video_ops mt9m114_ifp_video_ops = { + .s_stream = mt9m114_ifp_s_stream, + .g_frame_interval = mt9m114_ifp_g_frame_interval, + .s_frame_interval = mt9m114_ifp_s_frame_interval, +}; + +static const struct v4l2_subdev_pad_ops mt9m114_ifp_pad_ops = { + .init_cfg = mt9m114_ifp_init_cfg, + .enum_mbus_code = mt9m114_ifp_enum_mbus_code, + .enum_frame_size = mt9m114_ifp_enum_framesizes, + .enum_frame_interval = mt9m114_ifp_enum_frameintervals, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = mt9m114_ifp_set_fmt, + .get_selection = mt9m114_ifp_get_selection, + .set_selection = mt9m114_ifp_set_selection, +}; + +static const struct v4l2_subdev_ops mt9m114_ifp_ops = { + .video = &mt9m114_ifp_video_ops, + .pad = &mt9m114_ifp_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops mt9m114_ifp_internal_ops = { + .registered = mt9m114_ifp_registered, + .unregistered = mt9m114_ifp_unregistered, +}; + +static int mt9m114_ifp_init(struct mt9m114 *sensor) +{ + struct v4l2_subdev *sd = &sensor->ifp.sd; + struct media_pad *pads = sensor->ifp.pads; + struct v4l2_ctrl_handler *hdl = &sensor->ifp.hdl; + struct v4l2_ctrl *link_freq; + int ret; + + /* Initialize the subdev. */ + v4l2_i2c_subdev_init(sd, sensor->client, &mt9m114_ifp_ops); + v4l2_i2c_subdev_set_name(sd, sensor->client, NULL, " ifp"); + + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->internal_ops = &mt9m114_ifp_internal_ops; + + /* Initialize the media entity. */ + sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_ISP; + sd->entity.ops = &mt9m114_entity_ops; + pads[0].flags = MEDIA_PAD_FL_SINK; + pads[1].flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&sd->entity, 2, pads); + if (ret < 0) + return ret; + + sensor->ifp.frame_rate = MT9M114_DEF_FRAME_RATE; + + /* Initialize the control handler. */ + v4l2_ctrl_handler_init(hdl, 8); + v4l2_ctrl_new_std(hdl, &mt9m114_ifp_ctrl_ops, + V4L2_CID_AUTO_WHITE_BALANCE, + 0, 1, 1, 1); + v4l2_ctrl_new_std_menu(hdl, &mt9m114_ifp_ctrl_ops, + V4L2_CID_EXPOSURE_AUTO, + V4L2_EXPOSURE_MANUAL, 0, + V4L2_EXPOSURE_AUTO); + + link_freq = v4l2_ctrl_new_int_menu(hdl, &mt9m114_ifp_ctrl_ops, + V4L2_CID_LINK_FREQ, + sensor->bus_cfg.nr_of_link_frequencies - 1, + 0, sensor->bus_cfg.link_frequencies); + if (link_freq) + link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + v4l2_ctrl_new_std(hdl, &mt9m114_ifp_ctrl_ops, + V4L2_CID_PIXEL_RATE, + sensor->pixrate, sensor->pixrate, 1, + sensor->pixrate); + + sensor->ifp.tpg[MT9M114_TPG_PATTERN] = + v4l2_ctrl_new_std_menu_items(hdl, &mt9m114_ifp_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(mt9m114_test_pattern_menu) - 1, + 0, 0, mt9m114_test_pattern_menu); + sensor->ifp.tpg[MT9M114_TPG_RED] = + v4l2_ctrl_new_std(hdl, &mt9m114_ifp_ctrl_ops, + V4L2_CID_TEST_PATTERN_RED, + 0, 1023, 1, 1023); + sensor->ifp.tpg[MT9M114_TPG_GREEN] = + v4l2_ctrl_new_std(hdl, &mt9m114_ifp_ctrl_ops, + V4L2_CID_TEST_PATTERN_GREENR, + 0, 1023, 1, 1023); + sensor->ifp.tpg[MT9M114_TPG_BLUE] = + v4l2_ctrl_new_std(hdl, &mt9m114_ifp_ctrl_ops, + V4L2_CID_TEST_PATTERN_BLUE, + 0, 1023, 1, 1023); + + v4l2_ctrl_cluster(ARRAY_SIZE(sensor->ifp.tpg), sensor->ifp.tpg); + + if (hdl->error) { + ret = hdl->error; + goto error; + } + + sd->ctrl_handler = hdl; + sd->state_lock = hdl->lock; + + ret = v4l2_subdev_init_finalize(sd); + if (ret) + goto error; + + return 0; + +error: + v4l2_ctrl_handler_free(&sensor->ifp.hdl); + media_entity_cleanup(&sensor->ifp.sd.entity); + return ret; +} + +static void mt9m114_ifp_cleanup(struct mt9m114 *sensor) +{ + v4l2_ctrl_handler_free(&sensor->ifp.hdl); + media_entity_cleanup(&sensor->ifp.sd.entity); +} + +/* ----------------------------------------------------------------------------- + * Power Management + */ + +static int mt9m114_power_on(struct mt9m114 *sensor) +{ + int ret; + + /* Enable power and clocks. */ + ret = regulator_bulk_enable(ARRAY_SIZE(sensor->supplies), + sensor->supplies); + if (ret < 0) + return ret; + + ret = clk_prepare_enable(sensor->clk); + if (ret < 0) + goto error_regulator; + + /* Perform a hard reset if available, or a soft reset otherwise. */ + if (sensor->reset) { + long freq = clk_get_rate(sensor->clk); + unsigned int duration; + + /* + * The minimum duration is 50 clock cycles, thus typically + * around 2µs. Double it to be safe. + */ + duration = DIV_ROUND_UP(2 * 50 * 1000000, freq); + + gpiod_set_value(sensor->reset, 1); + udelay(duration); + gpiod_set_value(sensor->reset, 0); + } else { + /* + * The power may have just been turned on, we need to wait for + * the sensor to be ready to accept I2C commands. + */ + usleep_range(44500, 50000); + + cci_write(sensor->regmap, MT9M114_RESET_AND_MISC_CONTROL, + MT9M114_RESET_SOC, &ret); + cci_write(sensor->regmap, MT9M114_RESET_AND_MISC_CONTROL, 0, + &ret); + + if (ret < 0) { + dev_err(&sensor->client->dev, "Soft reset failed\n"); + goto error_clock; + } + } + + /* + * Wait for the sensor to be ready to accept I2C commands by polling the + * command register to wait for initialization to complete. + */ + usleep_range(44500, 50000); + + ret = mt9m114_poll_command(sensor, MT9M114_COMMAND_REGISTER_SET_STATE); + if (ret < 0) + goto error_clock; + + if (sensor->bus_cfg.bus_type == V4L2_MBUS_PARALLEL) { + /* + * In parallel mode (OE set to low), the sensor will enter the + * streaming state after initialization. Enter the standby + * manually to stop streaming. + */ + ret = mt9m114_set_state(sensor, + MT9M114_SYS_STATE_ENTER_STANDBY); + if (ret < 0) + goto error_clock; + } + + /* + * Before issuing any Set-State command, we must ensure that the sensor + * reaches the standby mode (either initiated manually above in + * parallel mode, or automatically after reset in MIPI mode). + */ + ret = mt9m114_poll_state(sensor, MT9M114_SYS_STATE_STANDBY); + if (ret < 0) + goto error_clock; + + return 0; + +error_clock: + clk_disable_unprepare(sensor->clk); +error_regulator: + regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies); + return ret; +} + +static void mt9m114_power_off(struct mt9m114 *sensor) +{ + clk_disable_unprepare(sensor->clk); + regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies); +} + +static int __maybe_unused mt9m114_runtime_resume(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + int ret; + + ret = mt9m114_power_on(sensor); + if (ret) + return ret; + + ret = mt9m114_initialize(sensor); + if (ret) { + mt9m114_power_off(sensor); + return ret; + } + + return 0; +} + +static int __maybe_unused mt9m114_runtime_suspend(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + + mt9m114_power_off(sensor); + + return 0; +} + +static const struct dev_pm_ops mt9m114_pm_ops = { + SET_RUNTIME_PM_OPS(mt9m114_runtime_suspend, mt9m114_runtime_resume, NULL) +}; + +/* ----------------------------------------------------------------------------- + * Probe & Remove + */ + +static int mt9m114_clk_init(struct mt9m114 *sensor) +{ + unsigned int link_freq; + + /* Hardcode the PLL multiplier and dividers to default settings. */ + sensor->pll.m = 32; + sensor->pll.n = 1; + sensor->pll.p = 7; + + /* + * Calculate the pixel rate and link frequency. The CSI-2 bus is clocked + * for 16-bit per pixel, transmitted in DDR over a single lane. For + * parallel mode, the sensor ouputs one pixel in two PIXCLK cycles. + */ + sensor->pixrate = clk_get_rate(sensor->clk) * sensor->pll.m + / ((sensor->pll.n + 1) * (sensor->pll.p + 1)); + + link_freq = sensor->bus_cfg.bus_type == V4L2_MBUS_CSI2_DPHY + ? sensor->pixrate * 8 : sensor->pixrate * 2; + + if (sensor->bus_cfg.nr_of_link_frequencies != 1 || + sensor->bus_cfg.link_frequencies[0] != link_freq) { + dev_err(&sensor->client->dev, "Unsupported DT link-frequencies\n"); + return -EINVAL; + } + + return 0; +} + +static int mt9m114_identify(struct mt9m114 *sensor) +{ + u64 major, minor, release, customer; + u64 value; + int ret; + + ret = cci_read(sensor->regmap, MT9M114_CHIP_ID, &value, NULL); + if (ret) { + dev_err(&sensor->client->dev, "Failed to read chip ID\n"); + return -ENXIO; + } + + if (value != 0x2481) { + dev_err(&sensor->client->dev, "Invalid chip ID 0x%04llx\n", + value); + return -ENXIO; + } + + cci_read(sensor->regmap, MT9M114_MON_MAJOR_VERSION, &major, &ret); + cci_read(sensor->regmap, MT9M114_MON_MINOR_VERSION, &minor, &ret); + cci_read(sensor->regmap, MT9M114_MON_RELEASE_VERSION, &release, &ret); + cci_read(sensor->regmap, MT9M114_CUSTOMER_REV, &customer, &ret); + if (ret) { + dev_err(&sensor->client->dev, "Failed to read version\n"); + return -ENXIO; + } + + dev_dbg(&sensor->client->dev, + "monitor v%llu.%llu.%04llx customer rev 0x%04llx\n", + major, minor, release, customer); + + return 0; +} + +static int mt9m114_parse_dt(struct mt9m114 *sensor) +{ + struct fwnode_handle *fwnode = dev_fwnode(&sensor->client->dev); + struct fwnode_handle *ep; + int ret; + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) { + dev_err(&sensor->client->dev, "No endpoint found\n"); + return -EINVAL; + } + + sensor->bus_cfg.bus_type = V4L2_MBUS_UNKNOWN; + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &sensor->bus_cfg); + fwnode_handle_put(ep); + if (ret < 0) { + dev_err(&sensor->client->dev, "Failed to parse endpoint\n"); + goto error; + } + + switch (sensor->bus_cfg.bus_type) { + case V4L2_MBUS_CSI2_DPHY: + case V4L2_MBUS_PARALLEL: + break; + + default: + dev_err(&sensor->client->dev, "unsupported bus type %u\n", + sensor->bus_cfg.bus_type); + ret = -EINVAL; + goto error; + } + + return 0; + +error: + v4l2_fwnode_endpoint_free(&sensor->bus_cfg); + return ret; +} + +static int mt9m114_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct mt9m114 *sensor; + int ret; + + sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + sensor->client = client; + + sensor->regmap = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(sensor->regmap)) { + dev_err(dev, "Unable to initialize I2C\n"); + return -ENODEV; + } + + ret = mt9m114_parse_dt(sensor); + if (ret < 0) + return ret; + + /* Acquire clocks, GPIOs and regulators. */ + sensor->clk = devm_clk_get(dev, NULL); + if (IS_ERR(sensor->clk)) { + ret = PTR_ERR(sensor->clk); + dev_err_probe(dev, ret, "Failed to get clock\n"); + goto error_ep_free; + } + + sensor->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(sensor->reset)) { + ret = PTR_ERR(sensor->reset); + dev_err_probe(dev, ret, "Failed to get reset GPIO\n"); + goto error_ep_free; + } + + sensor->supplies[0].supply = "vddio"; + sensor->supplies[1].supply = "vdd"; + sensor->supplies[2].supply = "vaa"; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(sensor->supplies), + sensor->supplies); + if (ret < 0) { + dev_err_probe(dev, ret, "Failed to get regulators\n"); + goto error_ep_free; + } + + ret = mt9m114_clk_init(sensor); + if (ret) + return ret; + + /* + * Identify the sensor. The driver supports runtime PM, but needs to + * work when runtime PM is disabled in the kernel. To that end, power + * the sensor on manually here, and initialize it after identification + * to reach the same state as if resumed through runtime PM. + */ + ret = mt9m114_power_on(sensor); + if (ret < 0) { + dev_err_probe(dev, ret, "Could not power on the device\n"); + return ret; + } + + ret = mt9m114_identify(sensor); + if (ret < 0) + goto error_power_off; + + ret = mt9m114_initialize(sensor); + if (ret < 0) + goto error_power_off; + + /* + * Enable runtime PM with autosuspend. As the device has been powered + * manually, mark it as active, and increase the usage count without + * resuming the device. + */ + pm_runtime_set_active(dev); + pm_runtime_get_noresume(dev); + pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + + /* Initialize the subdevices. */ + ret = mt9m114_pa_init(sensor); + if (ret < 0) + goto error_pm_cleanup; + + ret = mt9m114_ifp_init(sensor); + if (ret < 0) + goto error_pa_cleanup; + + ret = v4l2_async_register_subdev(&sensor->ifp.sd); + if (ret < 0) + goto error_ifp_cleanup; + + /* + * Decrease the PM usage count. The device will get suspended after the + * autosuspend delay, turning the power off. + */ + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return 0; + +error_ifp_cleanup: + mt9m114_ifp_cleanup(sensor); +error_pa_cleanup: + mt9m114_pa_cleanup(sensor); +error_pm_cleanup: + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); +error_power_off: + mt9m114_power_off(sensor); +error_ep_free: + v4l2_fwnode_endpoint_free(&sensor->bus_cfg); + return ret; +} + +static void mt9m114_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + struct device *dev = &client->dev; + + v4l2_async_unregister_subdev(&sensor->ifp.sd); + + mt9m114_ifp_cleanup(sensor); + mt9m114_pa_cleanup(sensor); + v4l2_fwnode_endpoint_free(&sensor->bus_cfg); + + /* + * Disable runtime PM. In case runtime PM is disabled in the kernel, + * make sure to turn power off manually. + */ + pm_runtime_disable(dev); + if (!pm_runtime_status_suspended(dev)) + mt9m114_power_off(sensor); + pm_runtime_set_suspended(dev); +} + +static const struct of_device_id mt9m114_of_ids[] = { + { .compatible = "onnn,mt9m114" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, mt9m114_of_ids); + +static struct i2c_driver mt9m114_driver = { + .driver = { + .name = "mt9m114", + .pm = &mt9m114_pm_ops, + .of_match_table = mt9m114_of_ids, + }, + .probe = mt9m114_probe, + .remove = mt9m114_remove, +}; + +module_i2c_driver(mt9m114_driver); + +MODULE_DESCRIPTION("onsemi MT9M114 Sensor Driver"); +MODULE_AUTHOR("Laurent Pinchart "); +MODULE_LICENSE("GPL"); -- GitLab From 852798cc8a45362ea7667c754b8ca0575a680a45 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 24 Sep 2023 18:32:50 +0300 Subject: [PATCH 0473/1451] media: i2c: imx219: Convert to CCI register access helpers Use the new common CCI register access helpers to replace the private register access helpers in the imx219 driver. This simplifies the driver by reducing the amount of code. Signed-off-by: Laurent Pinchart Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/Kconfig | 1 + drivers/media/i2c/imx219.c | 513 ++++++++++++++++--------------------- 2 files changed, 220 insertions(+), 294 deletions(-) diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 897d02f0b5523..59ee0ca2c978c 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -99,6 +99,7 @@ config VIDEO_IMX214 config VIDEO_IMX219 tristate "Sony IMX219 sensor support" + select V4L2_CCI_I2C help This is a Video4Linux2 sensor driver for the Sony IMX219 camera. diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index af29398c657dc..9d84f09bcced9 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -21,40 +21,49 @@ #include #include #include + +#include #include #include #include #include #include -#include -#define IMX219_REG_VALUE_08BIT 1 -#define IMX219_REG_VALUE_16BIT 2 +/* Chip ID */ +#define IMX219_REG_CHIP_ID CCI_REG16(0x0000) +#define IMX219_CHIP_ID 0x0219 -#define IMX219_REG_MODE_SELECT 0x0100 +#define IMX219_REG_MODE_SELECT CCI_REG8(0x0100) #define IMX219_MODE_STANDBY 0x00 #define IMX219_MODE_STREAMING 0x01 -/* Chip ID */ -#define IMX219_REG_CHIP_ID 0x0000 -#define IMX219_CHIP_ID 0x0219 - -/* External clock frequency is 24.0M */ -#define IMX219_XCLK_FREQ 24000000 +#define IMX219_REG_CSI_LANE_MODE CCI_REG8(0x0114) +#define IMX219_CSI_2_LANE_MODE 0x01 +#define IMX219_CSI_4_LANE_MODE 0x03 -/* Pixel rate is fixed for all the modes */ -#define IMX219_PIXEL_RATE 182400000 -#define IMX219_PIXEL_RATE_4LANE 280800000 +/* Analog gain control */ +#define IMX219_REG_ANALOG_GAIN CCI_REG8(0x0157) +#define IMX219_ANA_GAIN_MIN 0 +#define IMX219_ANA_GAIN_MAX 232 +#define IMX219_ANA_GAIN_STEP 1 +#define IMX219_ANA_GAIN_DEFAULT 0x0 -#define IMX219_DEFAULT_LINK_FREQ 456000000 -#define IMX219_DEFAULT_LINK_FREQ_4LANE 363000000 +/* Digital gain control */ +#define IMX219_REG_DIGITAL_GAIN CCI_REG16(0x0158) +#define IMX219_DGTL_GAIN_MIN 0x0100 +#define IMX219_DGTL_GAIN_MAX 0x0fff +#define IMX219_DGTL_GAIN_DEFAULT 0x0100 +#define IMX219_DGTL_GAIN_STEP 1 -#define IMX219_REG_CSI_LANE_MODE 0x0114 -#define IMX219_CSI_2_LANE_MODE 0x01 -#define IMX219_CSI_4_LANE_MODE 0x03 +/* Exposure control */ +#define IMX219_REG_EXPOSURE CCI_REG16(0x015a) +#define IMX219_EXPOSURE_MIN 4 +#define IMX219_EXPOSURE_STEP 1 +#define IMX219_EXPOSURE_DEFAULT 0x640 +#define IMX219_EXPOSURE_MAX 65535 /* V_TIMING internal */ -#define IMX219_REG_VTS 0x0160 +#define IMX219_REG_VTS CCI_REG16(0x0160) #define IMX219_VTS_15FPS 0x0dc6 #define IMX219_VTS_30FPS_1080P 0x06e3 #define IMX219_VTS_30FPS_BINNED 0x06e3 @@ -72,37 +81,16 @@ /* HBLANK control - read only */ #define IMX219_PPL_DEFAULT 3448 -/* Exposure control */ -#define IMX219_REG_EXPOSURE 0x015a -#define IMX219_EXPOSURE_MIN 4 -#define IMX219_EXPOSURE_STEP 1 -#define IMX219_EXPOSURE_DEFAULT 0x640 -#define IMX219_EXPOSURE_MAX 65535 - -/* Analog gain control */ -#define IMX219_REG_ANALOG_GAIN 0x0157 -#define IMX219_ANA_GAIN_MIN 0 -#define IMX219_ANA_GAIN_MAX 232 -#define IMX219_ANA_GAIN_STEP 1 -#define IMX219_ANA_GAIN_DEFAULT 0x0 - -/* Digital gain control */ -#define IMX219_REG_DIGITAL_GAIN 0x0158 -#define IMX219_DGTL_GAIN_MIN 0x0100 -#define IMX219_DGTL_GAIN_MAX 0x0fff -#define IMX219_DGTL_GAIN_DEFAULT 0x0100 -#define IMX219_DGTL_GAIN_STEP 1 - -#define IMX219_REG_ORIENTATION 0x0172 +#define IMX219_REG_ORIENTATION CCI_REG8(0x0172) /* Binning Mode */ -#define IMX219_REG_BINNING_MODE 0x0174 +#define IMX219_REG_BINNING_MODE CCI_REG16(0x0174) #define IMX219_BINNING_NONE 0x0000 #define IMX219_BINNING_2X2 0x0101 #define IMX219_BINNING_2X2_ANALOG 0x0303 /* Test Pattern Control */ -#define IMX219_REG_TEST_PATTERN 0x0600 +#define IMX219_REG_TEST_PATTERN CCI_REG16(0x0600) #define IMX219_TEST_PATTERN_DISABLE 0 #define IMX219_TEST_PATTERN_SOLID_COLOR 1 #define IMX219_TEST_PATTERN_COLOR_BARS 2 @@ -110,10 +98,10 @@ #define IMX219_TEST_PATTERN_PN9 4 /* Test pattern colour components */ -#define IMX219_REG_TESTP_RED 0x0602 -#define IMX219_REG_TESTP_GREENR 0x0604 -#define IMX219_REG_TESTP_BLUE 0x0606 -#define IMX219_REG_TESTP_GREENB 0x0608 +#define IMX219_REG_TESTP_RED CCI_REG16(0x0602) +#define IMX219_REG_TESTP_GREENR CCI_REG16(0x0604) +#define IMX219_REG_TESTP_BLUE CCI_REG16(0x0606) +#define IMX219_REG_TESTP_GREENB CCI_REG16(0x0608) #define IMX219_TESTP_COLOUR_MIN 0 #define IMX219_TESTP_COLOUR_MAX 0x03ff #define IMX219_TESTP_COLOUR_STEP 1 @@ -122,6 +110,16 @@ #define IMX219_TESTP_BLUE_DEFAULT 0 #define IMX219_TESTP_GREENB_DEFAULT 0 +/* External clock frequency is 24.0M */ +#define IMX219_XCLK_FREQ 24000000 + +/* Pixel rate is fixed for all the modes */ +#define IMX219_PIXEL_RATE 182400000 +#define IMX219_PIXEL_RATE_4LANE 280800000 + +#define IMX219_DEFAULT_LINK_FREQ 456000000 +#define IMX219_DEFAULT_LINK_FREQ_4LANE 363000000 + /* IMX219 native and active pixel array size. */ #define IMX219_NATIVE_WIDTH 3296U #define IMX219_NATIVE_HEIGHT 2480U @@ -130,14 +128,9 @@ #define IMX219_PIXEL_ARRAY_WIDTH 3280U #define IMX219_PIXEL_ARRAY_HEIGHT 2464U -struct imx219_reg { - u16 address; - u8 val; -}; - struct imx219_reg_list { unsigned int num_of_regs; - const struct imx219_reg *regs; + const struct cci_reg_sequence *regs; }; /* Mode : resolution and related config&values */ @@ -160,53 +153,53 @@ struct imx219_mode { bool binning; }; -static const struct imx219_reg imx219_common_regs[] = { - {0x0100, 0x00}, /* Mode Select */ +static const struct cci_reg_sequence imx219_common_regs[] = { + { CCI_REG8(0x0100), 0x00 }, /* Mode Select */ /* To Access Addresses 3000-5fff, send the following commands */ - {0x30eb, 0x0c}, - {0x30eb, 0x05}, - {0x300a, 0xff}, - {0x300b, 0xff}, - {0x30eb, 0x05}, - {0x30eb, 0x09}, + { CCI_REG8(0x30eb), 0x0c }, + { CCI_REG8(0x30eb), 0x05 }, + { CCI_REG8(0x300a), 0xff }, + { CCI_REG8(0x300b), 0xff }, + { CCI_REG8(0x30eb), 0x05 }, + { CCI_REG8(0x30eb), 0x09 }, /* PLL Clock Table */ - {0x0301, 0x05}, /* VTPXCK_DIV */ - {0x0303, 0x01}, /* VTSYSCK_DIV */ - {0x0304, 0x03}, /* PREPLLCK_VT_DIV 0x03 = AUTO set */ - {0x0305, 0x03}, /* PREPLLCK_OP_DIV 0x03 = AUTO set */ - {0x0306, 0x00}, /* PLL_VT_MPY */ - {0x0307, 0x39}, - {0x030b, 0x01}, /* OP_SYS_CLK_DIV */ - {0x030c, 0x00}, /* PLL_OP_MPY */ - {0x030d, 0x72}, + { CCI_REG8(0x0301), 0x05 }, /* VTPXCK_DIV */ + { CCI_REG8(0x0303), 0x01 }, /* VTSYSCK_DIV */ + { CCI_REG8(0x0304), 0x03 }, /* PREPLLCK_VT_DIV 0x03 = AUTO set */ + { CCI_REG8(0x0305), 0x03 }, /* PREPLLCK_OP_DIV 0x03 = AUTO set */ + { CCI_REG8(0x0306), 0x00 }, /* PLL_VT_MPY */ + { CCI_REG8(0x0307), 0x39 }, + { CCI_REG8(0x030b), 0x01 }, /* OP_SYS_CLK_DIV */ + { CCI_REG8(0x030c), 0x00 }, /* PLL_OP_MPY */ + { CCI_REG8(0x030d), 0x72 }, /* Undocumented registers */ - {0x455e, 0x00}, - {0x471e, 0x4b}, - {0x4767, 0x0f}, - {0x4750, 0x14}, - {0x4540, 0x00}, - {0x47b4, 0x14}, - {0x4713, 0x30}, - {0x478b, 0x10}, - {0x478f, 0x10}, - {0x4793, 0x10}, - {0x4797, 0x0e}, - {0x479b, 0x0e}, + { CCI_REG8(0x455e), 0x00 }, + { CCI_REG8(0x471e), 0x4b }, + { CCI_REG8(0x4767), 0x0f }, + { CCI_REG8(0x4750), 0x14 }, + { CCI_REG8(0x4540), 0x00 }, + { CCI_REG8(0x47b4), 0x14 }, + { CCI_REG8(0x4713), 0x30 }, + { CCI_REG8(0x478b), 0x10 }, + { CCI_REG8(0x478f), 0x10 }, + { CCI_REG8(0x4793), 0x10 }, + { CCI_REG8(0x4797), 0x0e }, + { CCI_REG8(0x479b), 0x0e }, /* Frame Bank Register Group "A" */ - {0x0162, 0x0d}, /* Line_Length_A */ - {0x0163, 0x78}, - {0x0170, 0x01}, /* X_ODD_INC_A */ - {0x0171, 0x01}, /* Y_ODD_INC_A */ + { CCI_REG8(0x0162), 0x0d }, /* Line_Length_A */ + { CCI_REG8(0x0163), 0x78 }, + { CCI_REG8(0x0170), 0x01 }, /* X_ODD_INC_A */ + { CCI_REG8(0x0171), 0x01 }, /* Y_ODD_INC_A */ /* Output setup registers */ - {0x0114, 0x01}, /* CSI 2-Lane Mode */ - {0x0128, 0x00}, /* DPHY Auto Mode */ - {0x012a, 0x18}, /* EXCK_Freq */ - {0x012b, 0x00}, + { CCI_REG8(0x0114), 0x01 }, /* CSI 2-Lane Mode */ + { CCI_REG8(0x0128), 0x00 }, /* DPHY Auto Mode */ + { CCI_REG8(0x012a), 0x18 }, /* EXCK_Freq */ + { CCI_REG8(0x012b), 0x00 }, }; /* @@ -214,92 +207,92 @@ static const struct imx219_reg imx219_common_regs[] = { * driver. * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7. */ -static const struct imx219_reg mode_3280x2464_regs[] = { - {0x0164, 0x00}, - {0x0165, 0x00}, - {0x0166, 0x0c}, - {0x0167, 0xcf}, - {0x0168, 0x00}, - {0x0169, 0x00}, - {0x016a, 0x09}, - {0x016b, 0x9f}, - {0x016c, 0x0c}, - {0x016d, 0xd0}, - {0x016e, 0x09}, - {0x016f, 0xa0}, - {0x0624, 0x0c}, - {0x0625, 0xd0}, - {0x0626, 0x09}, - {0x0627, 0xa0}, +static const struct cci_reg_sequence mode_3280x2464_regs[] = { + { CCI_REG8(0x0164), 0x00 }, + { CCI_REG8(0x0165), 0x00 }, + { CCI_REG8(0x0166), 0x0c }, + { CCI_REG8(0x0167), 0xcf }, + { CCI_REG8(0x0168), 0x00 }, + { CCI_REG8(0x0169), 0x00 }, + { CCI_REG8(0x016a), 0x09 }, + { CCI_REG8(0x016b), 0x9f }, + { CCI_REG8(0x016c), 0x0c }, + { CCI_REG8(0x016d), 0xd0 }, + { CCI_REG8(0x016e), 0x09 }, + { CCI_REG8(0x016f), 0xa0 }, + { CCI_REG8(0x0624), 0x0c }, + { CCI_REG8(0x0625), 0xd0 }, + { CCI_REG8(0x0626), 0x09 }, + { CCI_REG8(0x0627), 0xa0 }, }; -static const struct imx219_reg mode_1920_1080_regs[] = { - {0x0164, 0x02}, - {0x0165, 0xa8}, - {0x0166, 0x0a}, - {0x0167, 0x27}, - {0x0168, 0x02}, - {0x0169, 0xb4}, - {0x016a, 0x06}, - {0x016b, 0xeb}, - {0x016c, 0x07}, - {0x016d, 0x80}, - {0x016e, 0x04}, - {0x016f, 0x38}, - {0x0624, 0x07}, - {0x0625, 0x80}, - {0x0626, 0x04}, - {0x0627, 0x38}, +static const struct cci_reg_sequence mode_1920_1080_regs[] = { + { CCI_REG8(0x0164), 0x02 }, + { CCI_REG8(0x0165), 0xa8 }, + { CCI_REG8(0x0166), 0x0a }, + { CCI_REG8(0x0167), 0x27 }, + { CCI_REG8(0x0168), 0x02 }, + { CCI_REG8(0x0169), 0xb4 }, + { CCI_REG8(0x016a), 0x06 }, + { CCI_REG8(0x016b), 0xeb }, + { CCI_REG8(0x016c), 0x07 }, + { CCI_REG8(0x016d), 0x80 }, + { CCI_REG8(0x016e), 0x04 }, + { CCI_REG8(0x016f), 0x38 }, + { CCI_REG8(0x0624), 0x07 }, + { CCI_REG8(0x0625), 0x80 }, + { CCI_REG8(0x0626), 0x04 }, + { CCI_REG8(0x0627), 0x38 }, }; -static const struct imx219_reg mode_1640_1232_regs[] = { - {0x0164, 0x00}, - {0x0165, 0x00}, - {0x0166, 0x0c}, - {0x0167, 0xcf}, - {0x0168, 0x00}, - {0x0169, 0x00}, - {0x016a, 0x09}, - {0x016b, 0x9f}, - {0x016c, 0x06}, - {0x016d, 0x68}, - {0x016e, 0x04}, - {0x016f, 0xd0}, - {0x0624, 0x06}, - {0x0625, 0x68}, - {0x0626, 0x04}, - {0x0627, 0xd0}, +static const struct cci_reg_sequence mode_1640_1232_regs[] = { + { CCI_REG8(0x0164), 0x00 }, + { CCI_REG8(0x0165), 0x00 }, + { CCI_REG8(0x0166), 0x0c }, + { CCI_REG8(0x0167), 0xcf }, + { CCI_REG8(0x0168), 0x00 }, + { CCI_REG8(0x0169), 0x00 }, + { CCI_REG8(0x016a), 0x09 }, + { CCI_REG8(0x016b), 0x9f }, + { CCI_REG8(0x016c), 0x06 }, + { CCI_REG8(0x016d), 0x68 }, + { CCI_REG8(0x016e), 0x04 }, + { CCI_REG8(0x016f), 0xd0 }, + { CCI_REG8(0x0624), 0x06 }, + { CCI_REG8(0x0625), 0x68 }, + { CCI_REG8(0x0626), 0x04 }, + { CCI_REG8(0x0627), 0xd0 }, }; -static const struct imx219_reg mode_640_480_regs[] = { - {0x0164, 0x03}, - {0x0165, 0xe8}, - {0x0166, 0x08}, - {0x0167, 0xe7}, - {0x0168, 0x02}, - {0x0169, 0xf0}, - {0x016a, 0x06}, - {0x016b, 0xaf}, - {0x016c, 0x02}, - {0x016d, 0x80}, - {0x016e, 0x01}, - {0x016f, 0xe0}, - {0x0624, 0x06}, - {0x0625, 0x68}, - {0x0626, 0x04}, - {0x0627, 0xd0}, +static const struct cci_reg_sequence mode_640_480_regs[] = { + { CCI_REG8(0x0164), 0x03 }, + { CCI_REG8(0x0165), 0xe8 }, + { CCI_REG8(0x0166), 0x08 }, + { CCI_REG8(0x0167), 0xe7 }, + { CCI_REG8(0x0168), 0x02 }, + { CCI_REG8(0x0169), 0xf0 }, + { CCI_REG8(0x016a), 0x06 }, + { CCI_REG8(0x016b), 0xaf }, + { CCI_REG8(0x016c), 0x02 }, + { CCI_REG8(0x016d), 0x80 }, + { CCI_REG8(0x016e), 0x01 }, + { CCI_REG8(0x016f), 0xe0 }, + { CCI_REG8(0x0624), 0x06 }, + { CCI_REG8(0x0625), 0x68 }, + { CCI_REG8(0x0626), 0x04 }, + { CCI_REG8(0x0627), 0xd0 }, }; -static const struct imx219_reg raw8_framefmt_regs[] = { - {0x018c, 0x08}, - {0x018d, 0x08}, - {0x0309, 0x08}, +static const struct cci_reg_sequence raw8_framefmt_regs[] = { + { CCI_REG8(0x018c), 0x08 }, + { CCI_REG8(0x018d), 0x08 }, + { CCI_REG8(0x0309), 0x08 }, }; -static const struct imx219_reg raw10_framefmt_regs[] = { - {0x018c, 0x0a}, - {0x018d, 0x0a}, - {0x0309, 0x0a}, +static const struct cci_reg_sequence raw10_framefmt_regs[] = { + { CCI_REG8(0x018c), 0x0a }, + { CCI_REG8(0x018d), 0x0a }, + { CCI_REG8(0x0309), 0x0a }, }; static const s64 imx219_link_freq_menu[] = { @@ -460,6 +453,7 @@ struct imx219 { struct v4l2_subdev sd; struct media_pad pad; + struct regmap *regmap; struct clk *xclk; /* system clock to IMX219 */ u32 xclk_freq; @@ -488,78 +482,6 @@ static inline struct imx219 *to_imx219(struct v4l2_subdev *_sd) return container_of(_sd, struct imx219, sd); } -/* Read registers up to 2 at a time */ -static int imx219_read_reg(struct imx219 *imx219, u16 reg, u32 len, u32 *val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); - struct i2c_msg msgs[2]; - u8 addr_buf[2] = { reg >> 8, reg & 0xff }; - u8 data_buf[4] = { 0, }; - int ret; - - if (len > 4) - return -EINVAL; - - /* Write register address */ - msgs[0].addr = client->addr; - msgs[0].flags = 0; - msgs[0].len = ARRAY_SIZE(addr_buf); - msgs[0].buf = addr_buf; - - /* Read data from register */ - msgs[1].addr = client->addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = len; - msgs[1].buf = &data_buf[4 - len]; - - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret != ARRAY_SIZE(msgs)) - return -EIO; - - *val = get_unaligned_be32(data_buf); - - return 0; -} - -/* Write registers up to 2 at a time */ -static int imx219_write_reg(struct imx219 *imx219, u16 reg, u32 len, u32 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); - u8 buf[6]; - - if (len > 4) - return -EINVAL; - - put_unaligned_be16(reg, buf); - put_unaligned_be32(val << (8 * (4 - len)), buf + 2); - if (i2c_master_send(client, buf, len + 2) != len + 2) - return -EIO; - - return 0; -} - -/* Write a list of registers */ -static int imx219_write_regs(struct imx219 *imx219, - const struct imx219_reg *regs, u32 len) -{ - struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); - unsigned int i; - int ret; - - for (i = 0; i < len; i++) { - ret = imx219_write_reg(imx219, regs[i].address, 1, regs[i].val); - if (ret) { - dev_err_ratelimited(&client->dev, - "Failed to write reg 0x%4.4x. error = %d\n", - regs[i].address, ret); - - return ret; - } - } - - return 0; -} - /* Get bayer order based on flip setting. */ static u32 imx219_get_format_code(struct imx219 *imx219, u32 code) { @@ -583,7 +505,7 @@ static int imx219_set_ctrl(struct v4l2_ctrl *ctrl) struct imx219 *imx219 = container_of(ctrl->handler, struct imx219, ctrl_handler); struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); - int ret; + int ret = 0; if (ctrl->id == V4L2_CID_VBLANK) { int exposure_max, exposure_def; @@ -607,48 +529,45 @@ static int imx219_set_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case V4L2_CID_ANALOGUE_GAIN: - ret = imx219_write_reg(imx219, IMX219_REG_ANALOG_GAIN, - IMX219_REG_VALUE_08BIT, ctrl->val); + cci_write(imx219->regmap, IMX219_REG_ANALOG_GAIN, + ctrl->val, &ret); break; case V4L2_CID_EXPOSURE: - ret = imx219_write_reg(imx219, IMX219_REG_EXPOSURE, - IMX219_REG_VALUE_16BIT, ctrl->val); + cci_write(imx219->regmap, IMX219_REG_EXPOSURE, + ctrl->val, &ret); break; case V4L2_CID_DIGITAL_GAIN: - ret = imx219_write_reg(imx219, IMX219_REG_DIGITAL_GAIN, - IMX219_REG_VALUE_16BIT, ctrl->val); + cci_write(imx219->regmap, IMX219_REG_DIGITAL_GAIN, + ctrl->val, &ret); break; case V4L2_CID_TEST_PATTERN: - ret = imx219_write_reg(imx219, IMX219_REG_TEST_PATTERN, - IMX219_REG_VALUE_16BIT, - imx219_test_pattern_val[ctrl->val]); + cci_write(imx219->regmap, IMX219_REG_TEST_PATTERN, + imx219_test_pattern_val[ctrl->val], &ret); break; case V4L2_CID_HFLIP: case V4L2_CID_VFLIP: - ret = imx219_write_reg(imx219, IMX219_REG_ORIENTATION, 1, - imx219->hflip->val | - imx219->vflip->val << 1); + cci_write(imx219->regmap, IMX219_REG_ORIENTATION, + imx219->hflip->val | imx219->vflip->val << 1, &ret); break; case V4L2_CID_VBLANK: - ret = imx219_write_reg(imx219, IMX219_REG_VTS, - IMX219_REG_VALUE_16BIT, - imx219->mode->height + ctrl->val); + cci_write(imx219->regmap, IMX219_REG_VTS, + imx219->mode->height + ctrl->val, &ret); break; case V4L2_CID_TEST_PATTERN_RED: - ret = imx219_write_reg(imx219, IMX219_REG_TESTP_RED, - IMX219_REG_VALUE_16BIT, ctrl->val); + cci_write(imx219->regmap, IMX219_REG_TESTP_RED, + ctrl->val, &ret); break; case V4L2_CID_TEST_PATTERN_GREENR: - ret = imx219_write_reg(imx219, IMX219_REG_TESTP_GREENR, - IMX219_REG_VALUE_16BIT, ctrl->val); + cci_write(imx219->regmap, IMX219_REG_TESTP_GREENR, + ctrl->val, &ret); break; case V4L2_CID_TEST_PATTERN_BLUE: - ret = imx219_write_reg(imx219, IMX219_REG_TESTP_BLUE, - IMX219_REG_VALUE_16BIT, ctrl->val); + cci_write(imx219->regmap, IMX219_REG_TESTP_BLUE, + ctrl->val, &ret); break; case V4L2_CID_TEST_PATTERN_GREENB: - ret = imx219_write_reg(imx219, IMX219_REG_TESTP_GREENB, - IMX219_REG_VALUE_16BIT, ctrl->val); + cci_write(imx219->regmap, IMX219_REG_TESTP_GREENB, + ctrl->val, &ret); break; default: dev_info(&client->dev, @@ -799,15 +718,15 @@ static int imx219_set_framefmt(struct imx219 *imx219, case MEDIA_BUS_FMT_SGRBG8_1X8: case MEDIA_BUS_FMT_SGBRG8_1X8: case MEDIA_BUS_FMT_SBGGR8_1X8: - return imx219_write_regs(imx219, raw8_framefmt_regs, - ARRAY_SIZE(raw8_framefmt_regs)); + return cci_multi_reg_write(imx219->regmap, raw8_framefmt_regs, + ARRAY_SIZE(raw8_framefmt_regs), NULL); case MEDIA_BUS_FMT_SRGGB10_1X10: case MEDIA_BUS_FMT_SGRBG10_1X10: case MEDIA_BUS_FMT_SGBRG10_1X10: case MEDIA_BUS_FMT_SBGGR10_1X10: - return imx219_write_regs(imx219, raw10_framefmt_regs, - ARRAY_SIZE(raw10_framefmt_regs)); + return cci_multi_reg_write(imx219->regmap, raw10_framefmt_regs, + ARRAY_SIZE(raw10_framefmt_regs), NULL); } return -EINVAL; @@ -816,28 +735,24 @@ static int imx219_set_framefmt(struct imx219 *imx219, static int imx219_set_binning(struct imx219 *imx219, const struct v4l2_mbus_framefmt *format) { - if (!imx219->mode->binning) { - return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE, - IMX219_REG_VALUE_16BIT, - IMX219_BINNING_NONE); - } + if (!imx219->mode->binning) + return cci_write(imx219->regmap, IMX219_REG_BINNING_MODE, + IMX219_BINNING_NONE, NULL); switch (format->code) { case MEDIA_BUS_FMT_SRGGB8_1X8: case MEDIA_BUS_FMT_SGRBG8_1X8: case MEDIA_BUS_FMT_SGBRG8_1X8: case MEDIA_BUS_FMT_SBGGR8_1X8: - return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE, - IMX219_REG_VALUE_16BIT, - IMX219_BINNING_2X2_ANALOG); + return cci_write(imx219->regmap, IMX219_REG_BINNING_MODE, + IMX219_BINNING_2X2_ANALOG, NULL); case MEDIA_BUS_FMT_SRGGB10_1X10: case MEDIA_BUS_FMT_SGRBG10_1X10: case MEDIA_BUS_FMT_SGBRG10_1X10: case MEDIA_BUS_FMT_SBGGR10_1X10: - return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE, - IMX219_REG_VALUE_16BIT, - IMX219_BINNING_2X2); + return cci_write(imx219->regmap, IMX219_REG_BINNING_MODE, + IMX219_BINNING_2X2, NULL); } return -EINVAL; @@ -876,9 +791,9 @@ static int imx219_get_selection(struct v4l2_subdev *sd, static int imx219_configure_lanes(struct imx219 *imx219) { - return imx219_write_reg(imx219, IMX219_REG_CSI_LANE_MODE, - IMX219_REG_VALUE_08BIT, (imx219->lanes == 2) ? - IMX219_CSI_2_LANE_MODE : IMX219_CSI_4_LANE_MODE); + return cci_write(imx219->regmap, IMX219_REG_CSI_LANE_MODE, + imx219->lanes == 2 ? IMX219_CSI_2_LANE_MODE : + IMX219_CSI_4_LANE_MODE, NULL); }; static int imx219_start_streaming(struct imx219 *imx219, @@ -894,7 +809,8 @@ static int imx219_start_streaming(struct imx219 *imx219, return ret; /* Send all registers that are common to all modes */ - ret = imx219_write_regs(imx219, imx219_common_regs, ARRAY_SIZE(imx219_common_regs)); + ret = cci_multi_reg_write(imx219->regmap, imx219_common_regs, + ARRAY_SIZE(imx219_common_regs), NULL); if (ret) { dev_err(&client->dev, "%s failed to send mfg header\n", __func__); goto err_rpm_put; @@ -909,7 +825,8 @@ static int imx219_start_streaming(struct imx219 *imx219, /* Apply default values of current mode */ reg_list = &imx219->mode->reg_list; - ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs); + ret = cci_multi_reg_write(imx219->regmap, reg_list->regs, + reg_list->num_of_regs, NULL); if (ret) { dev_err(&client->dev, "%s failed to set mode\n", __func__); goto err_rpm_put; @@ -936,8 +853,8 @@ static int imx219_start_streaming(struct imx219 *imx219, goto err_rpm_put; /* set stream on register */ - ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT, - IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING); + ret = cci_write(imx219->regmap, IMX219_REG_MODE_SELECT, + IMX219_MODE_STREAMING, NULL); if (ret) goto err_rpm_put; @@ -958,8 +875,8 @@ static void imx219_stop_streaming(struct imx219 *imx219) int ret; /* set stream off register */ - ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT, - IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY); + ret = cci_write(imx219->regmap, IMX219_REG_MODE_SELECT, + IMX219_MODE_STANDBY, NULL); if (ret) dev_err(&client->dev, "%s failed to set stream\n", __func__); @@ -1058,10 +975,9 @@ static int imx219_identify_module(struct imx219 *imx219) { struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); int ret; - u32 val; + u64 val; - ret = imx219_read_reg(imx219, IMX219_REG_CHIP_ID, - IMX219_REG_VALUE_16BIT, &val); + ret = cci_read(imx219->regmap, IMX219_REG_CHIP_ID, &val, NULL); if (ret) { dev_err(&client->dev, "failed to read chip id %x\n", IMX219_CHIP_ID); @@ -1069,7 +985,7 @@ static int imx219_identify_module(struct imx219 *imx219) } if (val != IMX219_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x\n", + dev_err(&client->dev, "chip id mismatch: %x!=%llx\n", IMX219_CHIP_ID, val); return -EIO; } @@ -1293,6 +1209,13 @@ static int imx219_probe(struct i2c_client *client) if (imx219_check_hwcfg(dev, imx219)) return -EINVAL; + imx219->regmap = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(imx219->regmap)) { + ret = PTR_ERR(imx219->regmap); + dev_err(dev, "failed to initialize CCI: %d\n", ret); + return ret; + } + /* Get system clock (xclk) */ imx219->xclk = devm_clk_get(dev, NULL); if (IS_ERR(imx219->xclk)) { @@ -1336,17 +1259,19 @@ static int imx219_probe(struct i2c_client *client) * streaming is started, so upon power up switch the modes to: * streaming -> standby */ - ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT, - IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING); + ret = cci_write(imx219->regmap, IMX219_REG_MODE_SELECT, + IMX219_MODE_STREAMING, NULL); if (ret < 0) goto error_power_off; + usleep_range(100, 110); /* put sensor back to standby mode */ - ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT, - IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY); + ret = cci_write(imx219->regmap, IMX219_REG_MODE_SELECT, + IMX219_MODE_STANDBY, NULL); if (ret < 0) goto error_power_off; + usleep_range(100, 110); ret = imx219_init_controls(imx219); -- GitLab From 3e40c8db9ec55adcc844de63f2d1120f9a173e6a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 24 Sep 2023 18:32:51 +0300 Subject: [PATCH 0474/1451] media: i2c: imx219: Drop unused macros Drop a handful of macros that are not used and don't provide any value. Signed-off-by: Laurent Pinchart Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 9d84f09bcced9..a9f929fc58b01 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -72,12 +72,6 @@ #define IMX219_VBLANK_MIN 4 -/*Frame Length Line*/ -#define IMX219_FLL_MIN 0x08a6 -#define IMX219_FLL_MAX 0xffff -#define IMX219_FLL_STEP 1 -#define IMX219_FLL_DEFAULT 0x0c98 - /* HBLANK control - read only */ #define IMX219_PPL_DEFAULT 3448 @@ -105,10 +99,6 @@ #define IMX219_TESTP_COLOUR_MIN 0 #define IMX219_TESTP_COLOUR_MAX 0x03ff #define IMX219_TESTP_COLOUR_STEP 1 -#define IMX219_TESTP_RED_DEFAULT IMX219_TESTP_COLOUR_MAX -#define IMX219_TESTP_GREENR_DEFAULT 0 -#define IMX219_TESTP_BLUE_DEFAULT 0 -#define IMX219_TESTP_GREENB_DEFAULT 0 /* External clock frequency is 24.0M */ #define IMX219_XCLK_FREQ 24000000 -- GitLab From 1c9083565a4698ff072f1209e9450ff6c305e2cc Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 24 Sep 2023 18:32:52 +0300 Subject: [PATCH 0475/1451] media: i2c: imx219: Replace register addresses with macros Define macros for all the known registers used in the register arrays, and use them to replace the numerical addresses. This improves readability. Signed-off-by: Laurent Pinchart Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 169 ++++++++++++++++++------------------- 1 file changed, 81 insertions(+), 88 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index a9f929fc58b01..530b03d78e344 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -41,6 +41,13 @@ #define IMX219_CSI_2_LANE_MODE 0x01 #define IMX219_CSI_4_LANE_MODE 0x03 +#define IMX219_REG_DPHY_CTRL CCI_REG8(0x0128) +#define IMX219_DPHY_CTRL_TIMING_AUTO 0 +#define IMX219_DPHY_CTRL_TIMING_MANUAL 1 + +#define IMX219_REG_EXCK_FREQ CCI_REG16(0x012a) +#define IMX219_EXCK_FREQ(n) ((n) * 256) /* n expressed in MHz */ + /* Analog gain control */ #define IMX219_REG_ANALOG_GAIN CCI_REG8(0x0157) #define IMX219_ANA_GAIN_MIN 0 @@ -75,6 +82,15 @@ /* HBLANK control - read only */ #define IMX219_PPL_DEFAULT 3448 +#define IMX219_REG_LINE_LENGTH_A CCI_REG16(0x0162) +#define IMX219_REG_X_ADD_STA_A CCI_REG16(0x0164) +#define IMX219_REG_X_ADD_END_A CCI_REG16(0x0166) +#define IMX219_REG_Y_ADD_STA_A CCI_REG16(0x0168) +#define IMX219_REG_Y_ADD_END_A CCI_REG16(0x016a) +#define IMX219_REG_X_OUTPUT_SIZE CCI_REG16(0x016c) +#define IMX219_REG_Y_OUTPUT_SIZE CCI_REG16(0x016e) +#define IMX219_REG_X_ODD_INC_A CCI_REG8(0x0170) +#define IMX219_REG_Y_ODD_INC_A CCI_REG8(0x0171) #define IMX219_REG_ORIENTATION CCI_REG8(0x0172) /* Binning Mode */ @@ -83,6 +99,18 @@ #define IMX219_BINNING_2X2 0x0101 #define IMX219_BINNING_2X2_ANALOG 0x0303 +#define IMX219_REG_CSI_DATA_FORMAT_A CCI_REG16(0x018c) + +/* PLL Settings */ +#define IMX219_REG_VTPXCK_DIV CCI_REG8(0x0301) +#define IMX219_REG_VTSYCK_DIV CCI_REG8(0x0303) +#define IMX219_REG_PREPLLCK_VT_DIV CCI_REG8(0x0304) +#define IMX219_REG_PREPLLCK_OP_DIV CCI_REG8(0x0305) +#define IMX219_REG_PLL_VT_MPY CCI_REG16(0x0306) +#define IMX219_REG_OPPXCK_DIV CCI_REG8(0x0309) +#define IMX219_REG_OPSYCK_DIV CCI_REG8(0x030b) +#define IMX219_REG_PLL_OP_MPY CCI_REG16(0x030c) + /* Test Pattern Control */ #define IMX219_REG_TEST_PATTERN CCI_REG16(0x0600) #define IMX219_TEST_PATTERN_DISABLE 0 @@ -100,6 +128,9 @@ #define IMX219_TESTP_COLOUR_MAX 0x03ff #define IMX219_TESTP_COLOUR_STEP 1 +#define IMX219_REG_TP_WINDOW_WIDTH CCI_REG16(0x0624) +#define IMX219_REG_TP_WINDOW_HEIGHT CCI_REG16(0x0626) + /* External clock frequency is 24.0M */ #define IMX219_XCLK_FREQ 24000000 @@ -144,7 +175,7 @@ struct imx219_mode { }; static const struct cci_reg_sequence imx219_common_regs[] = { - { CCI_REG8(0x0100), 0x00 }, /* Mode Select */ + { IMX219_REG_MODE_SELECT, 0x00 }, /* Mode Select */ /* To Access Addresses 3000-5fff, send the following commands */ { CCI_REG8(0x30eb), 0x0c }, @@ -155,15 +186,13 @@ static const struct cci_reg_sequence imx219_common_regs[] = { { CCI_REG8(0x30eb), 0x09 }, /* PLL Clock Table */ - { CCI_REG8(0x0301), 0x05 }, /* VTPXCK_DIV */ - { CCI_REG8(0x0303), 0x01 }, /* VTSYSCK_DIV */ - { CCI_REG8(0x0304), 0x03 }, /* PREPLLCK_VT_DIV 0x03 = AUTO set */ - { CCI_REG8(0x0305), 0x03 }, /* PREPLLCK_OP_DIV 0x03 = AUTO set */ - { CCI_REG8(0x0306), 0x00 }, /* PLL_VT_MPY */ - { CCI_REG8(0x0307), 0x39 }, - { CCI_REG8(0x030b), 0x01 }, /* OP_SYS_CLK_DIV */ - { CCI_REG8(0x030c), 0x00 }, /* PLL_OP_MPY */ - { CCI_REG8(0x030d), 0x72 }, + { IMX219_REG_VTPXCK_DIV, 5 }, + { IMX219_REG_VTSYCK_DIV, 1 }, + { IMX219_REG_PREPLLCK_VT_DIV, 3 }, /* 0x03 = AUTO set */ + { IMX219_REG_PREPLLCK_OP_DIV, 3 }, /* 0x03 = AUTO set */ + { IMX219_REG_PLL_VT_MPY, 57 }, + { IMX219_REG_OPSYCK_DIV, 1 }, + { IMX219_REG_PLL_OP_MPY, 114 }, /* Undocumented registers */ { CCI_REG8(0x455e), 0x00 }, @@ -180,16 +209,14 @@ static const struct cci_reg_sequence imx219_common_regs[] = { { CCI_REG8(0x479b), 0x0e }, /* Frame Bank Register Group "A" */ - { CCI_REG8(0x0162), 0x0d }, /* Line_Length_A */ - { CCI_REG8(0x0163), 0x78 }, - { CCI_REG8(0x0170), 0x01 }, /* X_ODD_INC_A */ - { CCI_REG8(0x0171), 0x01 }, /* Y_ODD_INC_A */ + { IMX219_REG_LINE_LENGTH_A, 3448 }, + { IMX219_REG_X_ODD_INC_A, 1 }, + { IMX219_REG_Y_ODD_INC_A, 1 }, /* Output setup registers */ - { CCI_REG8(0x0114), 0x01 }, /* CSI 2-Lane Mode */ - { CCI_REG8(0x0128), 0x00 }, /* DPHY Auto Mode */ - { CCI_REG8(0x012a), 0x18 }, /* EXCK_Freq */ - { CCI_REG8(0x012b), 0x00 }, + { IMX219_REG_CSI_LANE_MODE, IMX219_CSI_2_LANE_MODE }, + { IMX219_REG_DPHY_CTRL, IMX219_DPHY_CTRL_TIMING_AUTO }, + { IMX219_REG_EXCK_FREQ, IMX219_EXCK_FREQ(IMX219_XCLK_FREQ / 1000000) }, }; /* @@ -198,91 +225,57 @@ static const struct cci_reg_sequence imx219_common_regs[] = { * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7. */ static const struct cci_reg_sequence mode_3280x2464_regs[] = { - { CCI_REG8(0x0164), 0x00 }, - { CCI_REG8(0x0165), 0x00 }, - { CCI_REG8(0x0166), 0x0c }, - { CCI_REG8(0x0167), 0xcf }, - { CCI_REG8(0x0168), 0x00 }, - { CCI_REG8(0x0169), 0x00 }, - { CCI_REG8(0x016a), 0x09 }, - { CCI_REG8(0x016b), 0x9f }, - { CCI_REG8(0x016c), 0x0c }, - { CCI_REG8(0x016d), 0xd0 }, - { CCI_REG8(0x016e), 0x09 }, - { CCI_REG8(0x016f), 0xa0 }, - { CCI_REG8(0x0624), 0x0c }, - { CCI_REG8(0x0625), 0xd0 }, - { CCI_REG8(0x0626), 0x09 }, - { CCI_REG8(0x0627), 0xa0 }, + { IMX219_REG_X_ADD_STA_A, 0 }, + { IMX219_REG_X_ADD_END_A, 3279 }, + { IMX219_REG_Y_ADD_STA_A, 0 }, + { IMX219_REG_Y_ADD_END_A, 2463 }, + { IMX219_REG_X_OUTPUT_SIZE, 3280 }, + { IMX219_REG_Y_OUTPUT_SIZE, 2464 }, + { IMX219_REG_TP_WINDOW_WIDTH, 3280 }, + { IMX219_REG_TP_WINDOW_HEIGHT, 2464 }, }; static const struct cci_reg_sequence mode_1920_1080_regs[] = { - { CCI_REG8(0x0164), 0x02 }, - { CCI_REG8(0x0165), 0xa8 }, - { CCI_REG8(0x0166), 0x0a }, - { CCI_REG8(0x0167), 0x27 }, - { CCI_REG8(0x0168), 0x02 }, - { CCI_REG8(0x0169), 0xb4 }, - { CCI_REG8(0x016a), 0x06 }, - { CCI_REG8(0x016b), 0xeb }, - { CCI_REG8(0x016c), 0x07 }, - { CCI_REG8(0x016d), 0x80 }, - { CCI_REG8(0x016e), 0x04 }, - { CCI_REG8(0x016f), 0x38 }, - { CCI_REG8(0x0624), 0x07 }, - { CCI_REG8(0x0625), 0x80 }, - { CCI_REG8(0x0626), 0x04 }, - { CCI_REG8(0x0627), 0x38 }, + { IMX219_REG_X_ADD_STA_A, 680 }, + { IMX219_REG_X_ADD_END_A, 2599 }, + { IMX219_REG_Y_ADD_STA_A, 692 }, + { IMX219_REG_Y_ADD_END_A, 1771 }, + { IMX219_REG_X_OUTPUT_SIZE, 1920 }, + { IMX219_REG_Y_OUTPUT_SIZE, 1080 }, + { IMX219_REG_TP_WINDOW_WIDTH, 1920 }, + { IMX219_REG_TP_WINDOW_HEIGHT, 1080 }, }; static const struct cci_reg_sequence mode_1640_1232_regs[] = { - { CCI_REG8(0x0164), 0x00 }, - { CCI_REG8(0x0165), 0x00 }, - { CCI_REG8(0x0166), 0x0c }, - { CCI_REG8(0x0167), 0xcf }, - { CCI_REG8(0x0168), 0x00 }, - { CCI_REG8(0x0169), 0x00 }, - { CCI_REG8(0x016a), 0x09 }, - { CCI_REG8(0x016b), 0x9f }, - { CCI_REG8(0x016c), 0x06 }, - { CCI_REG8(0x016d), 0x68 }, - { CCI_REG8(0x016e), 0x04 }, - { CCI_REG8(0x016f), 0xd0 }, - { CCI_REG8(0x0624), 0x06 }, - { CCI_REG8(0x0625), 0x68 }, - { CCI_REG8(0x0626), 0x04 }, - { CCI_REG8(0x0627), 0xd0 }, + { IMX219_REG_X_ADD_STA_A, 0 }, + { IMX219_REG_X_ADD_END_A, 3279 }, + { IMX219_REG_Y_ADD_STA_A, 0 }, + { IMX219_REG_Y_ADD_END_A, 2463 }, + { IMX219_REG_X_OUTPUT_SIZE, 1640 }, + { IMX219_REG_Y_OUTPUT_SIZE, 1232 }, + { IMX219_REG_TP_WINDOW_WIDTH, 1640 }, + { IMX219_REG_TP_WINDOW_HEIGHT, 1232 }, }; static const struct cci_reg_sequence mode_640_480_regs[] = { - { CCI_REG8(0x0164), 0x03 }, - { CCI_REG8(0x0165), 0xe8 }, - { CCI_REG8(0x0166), 0x08 }, - { CCI_REG8(0x0167), 0xe7 }, - { CCI_REG8(0x0168), 0x02 }, - { CCI_REG8(0x0169), 0xf0 }, - { CCI_REG8(0x016a), 0x06 }, - { CCI_REG8(0x016b), 0xaf }, - { CCI_REG8(0x016c), 0x02 }, - { CCI_REG8(0x016d), 0x80 }, - { CCI_REG8(0x016e), 0x01 }, - { CCI_REG8(0x016f), 0xe0 }, - { CCI_REG8(0x0624), 0x06 }, - { CCI_REG8(0x0625), 0x68 }, - { CCI_REG8(0x0626), 0x04 }, - { CCI_REG8(0x0627), 0xd0 }, + { IMX219_REG_X_ADD_STA_A, 1000 }, + { IMX219_REG_X_ADD_END_A, 2279 }, + { IMX219_REG_Y_ADD_STA_A, 752 }, + { IMX219_REG_Y_ADD_END_A, 1711 }, + { IMX219_REG_X_OUTPUT_SIZE, 640 }, + { IMX219_REG_Y_OUTPUT_SIZE, 480 }, + { IMX219_REG_TP_WINDOW_WIDTH, 1640 }, + { IMX219_REG_TP_WINDOW_HEIGHT, 1232 }, }; static const struct cci_reg_sequence raw8_framefmt_regs[] = { - { CCI_REG8(0x018c), 0x08 }, - { CCI_REG8(0x018d), 0x08 }, - { CCI_REG8(0x0309), 0x08 }, + { IMX219_REG_CSI_DATA_FORMAT_A, 0x0808 }, + { IMX219_REG_OPPXCK_DIV, 8 }, }; static const struct cci_reg_sequence raw10_framefmt_regs[] = { - { CCI_REG8(0x018c), 0x0a }, - { CCI_REG8(0x018d), 0x0a }, - { CCI_REG8(0x0309), 0x0a }, + { IMX219_REG_CSI_DATA_FORMAT_A, 0x0a0a }, + { IMX219_REG_OPPXCK_DIV, 10 }, }; static const s64 imx219_link_freq_menu[] = { -- GitLab From ec80c606cca5f7a676febde10d63f5532f57e8e7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 24 Sep 2023 18:32:53 +0300 Subject: [PATCH 0476/1451] media: i2c: imx219: Drop IMX219_REG_CSI_LANE_MODE from common regs array The IMX219_REG_CSI_LANE_MODE is configured twice, once with a hardcoded value in the imx219_common_regs registers array, and once with the value appropriate for the system in imx219_configure_lanes(). The latter is enough, drop the former. Fixes: ceddfd4493b3 ("media: i2c: imx219: Support four-lane operation") Suggested-by: Dave Stevenson Signed-off-by: Laurent Pinchart Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 530b03d78e344..a14de8f3dee73 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -214,7 +214,6 @@ static const struct cci_reg_sequence imx219_common_regs[] = { { IMX219_REG_Y_ODD_INC_A, 1 }, /* Output setup registers */ - { IMX219_REG_CSI_LANE_MODE, IMX219_CSI_2_LANE_MODE }, { IMX219_REG_DPHY_CTRL, IMX219_DPHY_CTRL_TIMING_AUTO }, { IMX219_REG_EXCK_FREQ, IMX219_EXCK_FREQ(IMX219_XCLK_FREQ / 1000000) }, }; -- GitLab From 55c3ec033b7e3353d1bed7ab96de8e9abc02fe3a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 24 Sep 2023 18:32:54 +0300 Subject: [PATCH 0477/1451] media: i2c: imx219: Fix test pattern window for 640x480 mode The 640x480 mode specifies incorrect values for the TP_WINDOW_WIDTH and TP_WINDOW_HEIGHT registers, which likely got copied from the 1640x1232 mode. They should be identical to the X_OUTPUT_SIZE and Y_OUTPUT_SIZE registers as for all the other modes, to avoid cropping the test pattern. Fix them. Signed-off-by: Laurent Pinchart Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index a14de8f3dee73..cf55c59cbb7f4 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -263,8 +263,8 @@ static const struct cci_reg_sequence mode_640_480_regs[] = { { IMX219_REG_Y_ADD_END_A, 1711 }, { IMX219_REG_X_OUTPUT_SIZE, 640 }, { IMX219_REG_Y_OUTPUT_SIZE, 480 }, - { IMX219_REG_TP_WINDOW_WIDTH, 1640 }, - { IMX219_REG_TP_WINDOW_HEIGHT, 1232 }, + { IMX219_REG_TP_WINDOW_WIDTH, 640 }, + { IMX219_REG_TP_WINDOW_HEIGHT, 480 }, }; static const struct cci_reg_sequence raw8_framefmt_regs[] = { -- GitLab From 8921687278d4d5d5c936ea1c106f1a8f4c04f7fd Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 24 Sep 2023 18:32:55 +0300 Subject: [PATCH 0478/1451] media: i2c: imx219: Set mode registers programmatically Replace the per-mode register arrays with code that sets the same register values using the mode definitions. This avoids duplicating information in two different places. The error check for invalid formats in imx219_set_framefmt() is dropped as the format is guaranteed to be valid. Signed-off-by: Laurent Pinchart Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 134 ++++++++++--------------------------- 1 file changed, 36 insertions(+), 98 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index cf55c59cbb7f4..927ab106cea68 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -149,11 +149,6 @@ #define IMX219_PIXEL_ARRAY_WIDTH 3280U #define IMX219_PIXEL_ARRAY_HEIGHT 2464U -struct imx219_reg_list { - unsigned int num_of_regs; - const struct cci_reg_sequence *regs; -}; - /* Mode : resolution and related config&values */ struct imx219_mode { /* Frame width */ @@ -167,9 +162,6 @@ struct imx219_mode { /* V-timing */ unsigned int vts_def; - /* Default register values */ - struct imx219_reg_list reg_list; - /* 2x2 binning is used */ bool binning; }; @@ -218,65 +210,6 @@ static const struct cci_reg_sequence imx219_common_regs[] = { { IMX219_REG_EXCK_FREQ, IMX219_EXCK_FREQ(IMX219_XCLK_FREQ / 1000000) }, }; -/* - * Register sets lifted off the i2C interface from the Raspberry Pi firmware - * driver. - * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7. - */ -static const struct cci_reg_sequence mode_3280x2464_regs[] = { - { IMX219_REG_X_ADD_STA_A, 0 }, - { IMX219_REG_X_ADD_END_A, 3279 }, - { IMX219_REG_Y_ADD_STA_A, 0 }, - { IMX219_REG_Y_ADD_END_A, 2463 }, - { IMX219_REG_X_OUTPUT_SIZE, 3280 }, - { IMX219_REG_Y_OUTPUT_SIZE, 2464 }, - { IMX219_REG_TP_WINDOW_WIDTH, 3280 }, - { IMX219_REG_TP_WINDOW_HEIGHT, 2464 }, -}; - -static const struct cci_reg_sequence mode_1920_1080_regs[] = { - { IMX219_REG_X_ADD_STA_A, 680 }, - { IMX219_REG_X_ADD_END_A, 2599 }, - { IMX219_REG_Y_ADD_STA_A, 692 }, - { IMX219_REG_Y_ADD_END_A, 1771 }, - { IMX219_REG_X_OUTPUT_SIZE, 1920 }, - { IMX219_REG_Y_OUTPUT_SIZE, 1080 }, - { IMX219_REG_TP_WINDOW_WIDTH, 1920 }, - { IMX219_REG_TP_WINDOW_HEIGHT, 1080 }, -}; - -static const struct cci_reg_sequence mode_1640_1232_regs[] = { - { IMX219_REG_X_ADD_STA_A, 0 }, - { IMX219_REG_X_ADD_END_A, 3279 }, - { IMX219_REG_Y_ADD_STA_A, 0 }, - { IMX219_REG_Y_ADD_END_A, 2463 }, - { IMX219_REG_X_OUTPUT_SIZE, 1640 }, - { IMX219_REG_Y_OUTPUT_SIZE, 1232 }, - { IMX219_REG_TP_WINDOW_WIDTH, 1640 }, - { IMX219_REG_TP_WINDOW_HEIGHT, 1232 }, -}; - -static const struct cci_reg_sequence mode_640_480_regs[] = { - { IMX219_REG_X_ADD_STA_A, 1000 }, - { IMX219_REG_X_ADD_END_A, 2279 }, - { IMX219_REG_Y_ADD_STA_A, 752 }, - { IMX219_REG_Y_ADD_END_A, 1711 }, - { IMX219_REG_X_OUTPUT_SIZE, 640 }, - { IMX219_REG_Y_OUTPUT_SIZE, 480 }, - { IMX219_REG_TP_WINDOW_WIDTH, 640 }, - { IMX219_REG_TP_WINDOW_HEIGHT, 480 }, -}; - -static const struct cci_reg_sequence raw8_framefmt_regs[] = { - { IMX219_REG_CSI_DATA_FORMAT_A, 0x0808 }, - { IMX219_REG_OPPXCK_DIV, 8 }, -}; - -static const struct cci_reg_sequence raw10_framefmt_regs[] = { - { IMX219_REG_CSI_DATA_FORMAT_A, 0x0a0a }, - { IMX219_REG_OPPXCK_DIV, 10 }, -}; - static const s64 imx219_link_freq_menu[] = { IMX219_DEFAULT_LINK_FREQ, }; @@ -372,10 +305,6 @@ static const struct imx219_mode supported_modes[] = { .height = 2464 }, .vts_def = IMX219_VTS_15FPS, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs), - .regs = mode_3280x2464_regs, - }, .binning = false, }, { @@ -389,10 +318,6 @@ static const struct imx219_mode supported_modes[] = { .height = 1080 }, .vts_def = IMX219_VTS_30FPS_1080P, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_1920_1080_regs), - .regs = mode_1920_1080_regs, - }, .binning = false, }, { @@ -406,10 +331,6 @@ static const struct imx219_mode supported_modes[] = { .height = 2464 }, .vts_def = IMX219_VTS_30FPS_BINNED, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_1640_1232_regs), - .regs = mode_1640_1232_regs, - }, .binning = true, }, { @@ -423,10 +344,6 @@ static const struct imx219_mode supported_modes[] = { .height = 960 }, .vts_def = IMX219_VTS_30FPS_640x480, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_640_480_regs), - .regs = mode_640_480_regs, - }, .binning = true, }, }; @@ -695,23 +612,53 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, static int imx219_set_framefmt(struct imx219 *imx219, const struct v4l2_mbus_framefmt *format) { + const struct imx219_mode *mode = imx219->mode; + unsigned int bpp; + int ret = 0; + switch (format->code) { case MEDIA_BUS_FMT_SRGGB8_1X8: case MEDIA_BUS_FMT_SGRBG8_1X8: case MEDIA_BUS_FMT_SGBRG8_1X8: case MEDIA_BUS_FMT_SBGGR8_1X8: - return cci_multi_reg_write(imx219->regmap, raw8_framefmt_regs, - ARRAY_SIZE(raw8_framefmt_regs), NULL); + bpp = 8; + break; case MEDIA_BUS_FMT_SRGGB10_1X10: case MEDIA_BUS_FMT_SGRBG10_1X10: case MEDIA_BUS_FMT_SGBRG10_1X10: case MEDIA_BUS_FMT_SBGGR10_1X10: - return cci_multi_reg_write(imx219->regmap, raw10_framefmt_regs, - ARRAY_SIZE(raw10_framefmt_regs), NULL); + default: + bpp = 10; + break; } - return -EINVAL; + cci_write(imx219->regmap, IMX219_REG_X_ADD_STA_A, + mode->crop.left - IMX219_PIXEL_ARRAY_LEFT, &ret); + cci_write(imx219->regmap, IMX219_REG_X_ADD_END_A, + mode->crop.left - IMX219_PIXEL_ARRAY_LEFT + mode->crop.width - 1, + &ret); + cci_write(imx219->regmap, IMX219_REG_Y_ADD_STA_A, + mode->crop.top - IMX219_PIXEL_ARRAY_TOP, &ret); + cci_write(imx219->regmap, IMX219_REG_Y_ADD_END_A, + mode->crop.top - IMX219_PIXEL_ARRAY_TOP + mode->crop.height - 1, + &ret); + + cci_write(imx219->regmap, IMX219_REG_X_OUTPUT_SIZE, + format->width, &ret); + cci_write(imx219->regmap, IMX219_REG_Y_OUTPUT_SIZE, + format->height, &ret); + + cci_write(imx219->regmap, IMX219_REG_TP_WINDOW_WIDTH, + format->width, &ret); + cci_write(imx219->regmap, IMX219_REG_TP_WINDOW_HEIGHT, + format->height, &ret); + + cci_write(imx219->regmap, IMX219_REG_CSI_DATA_FORMAT_A, + (bpp << 8) | bpp, &ret); + cci_write(imx219->regmap, IMX219_REG_OPPXCK_DIV, bpp, &ret); + + return ret; } static int imx219_set_binning(struct imx219 *imx219, @@ -783,7 +730,6 @@ static int imx219_start_streaming(struct imx219 *imx219, { struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); const struct v4l2_mbus_framefmt *format; - const struct imx219_reg_list *reg_list; int ret; ret = pm_runtime_resume_and_get(&client->dev); @@ -805,15 +751,7 @@ static int imx219_start_streaming(struct imx219 *imx219, goto err_rpm_put; } - /* Apply default values of current mode */ - reg_list = &imx219->mode->reg_list; - ret = cci_multi_reg_write(imx219->regmap, reg_list->regs, - reg_list->num_of_regs, NULL); - if (ret) { - dev_err(&client->dev, "%s failed to set mode\n", __func__); - goto err_rpm_put; - } - + /* Apply format and crop settings. */ format = v4l2_subdev_get_pad_format(&imx219->sd, state, 0); ret = imx219_set_framefmt(imx219, format); if (ret) { -- GitLab From cff09e76bf7940e2a82d003d80ca89824005008d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 24 Sep 2023 18:32:56 +0300 Subject: [PATCH 0479/1451] media: i2c: imx219: Merge format and binning setting functions The imx219_set_binning() function sets registers based on the bpp value, which is computed in imx219_set_framefmt(). As both functions are called from the same place consecutively, and set registers based on the selected mode, merge them together to simplify the code. Signed-off-by: Laurent Pinchart Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 43 +++++++++----------------------------- 1 file changed, 10 insertions(+), 33 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 927ab106cea68..140924445a61c 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -614,6 +614,7 @@ static int imx219_set_framefmt(struct imx219 *imx219, { const struct imx219_mode *mode = imx219->mode; unsigned int bpp; + u64 bin_mode; int ret = 0; switch (format->code) { @@ -644,6 +645,15 @@ static int imx219_set_framefmt(struct imx219 *imx219, mode->crop.top - IMX219_PIXEL_ARRAY_TOP + mode->crop.height - 1, &ret); + if (!imx219->mode->binning) + bin_mode = IMX219_BINNING_NONE; + else if (bpp == 8) + bin_mode = IMX219_BINNING_2X2_ANALOG; + else + bin_mode = IMX219_BINNING_2X2; + + cci_write(imx219->regmap, IMX219_REG_BINNING_MODE, bin_mode, &ret); + cci_write(imx219->regmap, IMX219_REG_X_OUTPUT_SIZE, format->width, &ret); cci_write(imx219->regmap, IMX219_REG_Y_OUTPUT_SIZE, @@ -661,32 +671,6 @@ static int imx219_set_framefmt(struct imx219 *imx219, return ret; } -static int imx219_set_binning(struct imx219 *imx219, - const struct v4l2_mbus_framefmt *format) -{ - if (!imx219->mode->binning) - return cci_write(imx219->regmap, IMX219_REG_BINNING_MODE, - IMX219_BINNING_NONE, NULL); - - switch (format->code) { - case MEDIA_BUS_FMT_SRGGB8_1X8: - case MEDIA_BUS_FMT_SGRBG8_1X8: - case MEDIA_BUS_FMT_SGBRG8_1X8: - case MEDIA_BUS_FMT_SBGGR8_1X8: - return cci_write(imx219->regmap, IMX219_REG_BINNING_MODE, - IMX219_BINNING_2X2_ANALOG, NULL); - - case MEDIA_BUS_FMT_SRGGB10_1X10: - case MEDIA_BUS_FMT_SGRBG10_1X10: - case MEDIA_BUS_FMT_SGBRG10_1X10: - case MEDIA_BUS_FMT_SBGGR10_1X10: - return cci_write(imx219->regmap, IMX219_REG_BINNING_MODE, - IMX219_BINNING_2X2, NULL); - } - - return -EINVAL; -} - static int imx219_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) @@ -760,13 +744,6 @@ static int imx219_start_streaming(struct imx219 *imx219, goto err_rpm_put; } - ret = imx219_set_binning(imx219, format); - if (ret) { - dev_err(&client->dev, "%s failed to set binning: %d\n", - __func__, ret); - goto err_rpm_put; - } - /* Apply customized values from user */ ret = __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler); if (ret) -- GitLab From 2ae504a561dbb31e5fb0a21f242f07e8c91cce61 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 24 Sep 2023 18:32:57 +0300 Subject: [PATCH 0480/1451] media: i2c: imx219: Initialize ycbcr_enc While the ycbcr_enc field doesn't apply to raw formats, leaving it uninitialized makes the driver behave in a less deterministic way. Fix it by picking the default value for the colorspace. Signed-off-by: Laurent Pinchart Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 140924445a61c..2e1fbeef11a88 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -495,6 +495,7 @@ static void imx219_update_pad_format(struct imx219 *imx219, fmt->height = mode->height; fmt->field = V4L2_FIELD_NONE; fmt->colorspace = V4L2_COLORSPACE_RAW; + fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; fmt->xfer_func = V4L2_XFER_FUNC_NONE; } -- GitLab From 00eb22782bb15b04dddc8471bbcee68b7613ba0f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 24 Sep 2023 18:32:58 +0300 Subject: [PATCH 0481/1451] media: i2c: imx219: Use active crop rectangle to configure registers Configure the crop-related registers from the values stored in the active crop rectangle instead of the mode structure. This removes usage of the mode from the imx219_set_framefmt(). No functional change is intended. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 2e1fbeef11a88..562cfee87b247 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -611,13 +611,17 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, } static int imx219_set_framefmt(struct imx219 *imx219, - const struct v4l2_mbus_framefmt *format) + struct v4l2_subdev_state *state) { - const struct imx219_mode *mode = imx219->mode; + const struct v4l2_mbus_framefmt *format; + const struct v4l2_rect *crop; unsigned int bpp; u64 bin_mode; int ret = 0; + format = v4l2_subdev_get_pad_format(&imx219->sd, state, 0); + crop = v4l2_subdev_get_pad_crop(&imx219->sd, state, 0); + switch (format->code) { case MEDIA_BUS_FMT_SRGGB8_1X8: case MEDIA_BUS_FMT_SGRBG8_1X8: @@ -636,15 +640,13 @@ static int imx219_set_framefmt(struct imx219 *imx219, } cci_write(imx219->regmap, IMX219_REG_X_ADD_STA_A, - mode->crop.left - IMX219_PIXEL_ARRAY_LEFT, &ret); + crop->left - IMX219_PIXEL_ARRAY_LEFT, &ret); cci_write(imx219->regmap, IMX219_REG_X_ADD_END_A, - mode->crop.left - IMX219_PIXEL_ARRAY_LEFT + mode->crop.width - 1, - &ret); + crop->left - IMX219_PIXEL_ARRAY_LEFT + crop->width - 1, &ret); cci_write(imx219->regmap, IMX219_REG_Y_ADD_STA_A, - mode->crop.top - IMX219_PIXEL_ARRAY_TOP, &ret); + crop->top - IMX219_PIXEL_ARRAY_TOP, &ret); cci_write(imx219->regmap, IMX219_REG_Y_ADD_END_A, - mode->crop.top - IMX219_PIXEL_ARRAY_TOP + mode->crop.height - 1, - &ret); + crop->top - IMX219_PIXEL_ARRAY_TOP + crop->height - 1, &ret); if (!imx219->mode->binning) bin_mode = IMX219_BINNING_NONE; @@ -714,7 +716,6 @@ static int imx219_start_streaming(struct imx219 *imx219, struct v4l2_subdev_state *state) { struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); - const struct v4l2_mbus_framefmt *format; int ret; ret = pm_runtime_resume_and_get(&client->dev); @@ -737,8 +738,7 @@ static int imx219_start_streaming(struct imx219 *imx219, } /* Apply format and crop settings. */ - format = v4l2_subdev_get_pad_format(&imx219->sd, state, 0); - ret = imx219_set_framefmt(imx219, format); + ret = imx219_set_framefmt(imx219, state); if (ret) { dev_err(&client->dev, "%s failed to set frame format: %d\n", __func__, ret); -- GitLab From c59d77be1b8349757660216e20db8cac75e6c967 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 24 Sep 2023 18:32:59 +0300 Subject: [PATCH 0482/1451] media: i2c: imx219: Infer binning settings from format and crop Compare the format and crop rectangle dimensions to infer binning settings, instead of storing the binning mode in the imx219_mode structure. This removes duplicate information from the mode. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 562cfee87b247..bc836cd13ef50 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -161,9 +161,6 @@ struct imx219_mode { /* V-timing */ unsigned int vts_def; - - /* 2x2 binning is used */ - bool binning; }; static const struct cci_reg_sequence imx219_common_regs[] = { @@ -305,7 +302,6 @@ static const struct imx219_mode supported_modes[] = { .height = 2464 }, .vts_def = IMX219_VTS_15FPS, - .binning = false, }, { /* 1080P 30fps cropped */ @@ -318,7 +314,6 @@ static const struct imx219_mode supported_modes[] = { .height = 1080 }, .vts_def = IMX219_VTS_30FPS_1080P, - .binning = false, }, { /* 2x2 binned 30fps mode */ @@ -331,7 +326,6 @@ static const struct imx219_mode supported_modes[] = { .height = 2464 }, .vts_def = IMX219_VTS_30FPS_BINNED, - .binning = true, }, { /* 640x480 30fps mode */ @@ -344,7 +338,6 @@ static const struct imx219_mode supported_modes[] = { .height = 960 }, .vts_def = IMX219_VTS_30FPS_640x480, - .binning = true, }, }; @@ -648,7 +641,7 @@ static int imx219_set_framefmt(struct imx219 *imx219, cci_write(imx219->regmap, IMX219_REG_Y_ADD_END_A, crop->top - IMX219_PIXEL_ARRAY_TOP + crop->height - 1, &ret); - if (!imx219->mode->binning) + if (format->width == crop->width && format->height == crop->height) bin_mode = IMX219_BINNING_NONE; else if (bpp == 8) bin_mode = IMX219_BINNING_2X2_ANALOG; -- GitLab From aa86ac42eec4dd7e987c12390a0a487187e2d9ae Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 24 Sep 2023 18:33:00 +0300 Subject: [PATCH 0483/1451] media: i2c: imx219: Access height from active format in imx219_set_ctrl Use the active format height instead of the mode height in imx219_set_ctrl(). This prepares for dropping the mode field from the imx219 structure. The state is retrieved using v4l2_subdev_get_locked_active_state() as the subdev active state and the control handler share the same lock. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index bc836cd13ef50..f4f684bda4fab 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -397,13 +397,18 @@ static int imx219_set_ctrl(struct v4l2_ctrl *ctrl) struct imx219 *imx219 = container_of(ctrl->handler, struct imx219, ctrl_handler); struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); + const struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; int ret = 0; + state = v4l2_subdev_get_locked_active_state(&imx219->sd); + format = v4l2_subdev_get_pad_format(&imx219->sd, state, 0); + if (ctrl->id == V4L2_CID_VBLANK) { int exposure_max, exposure_def; /* Update max exposure while meeting expected vblanking */ - exposure_max = imx219->mode->height + ctrl->val - 4; + exposure_max = format->height + ctrl->val - 4; exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? exposure_max : IMX219_EXPOSURE_DEFAULT; __v4l2_ctrl_modify_range(imx219->exposure, @@ -443,7 +448,7 @@ static int imx219_set_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_VBLANK: cci_write(imx219->regmap, IMX219_REG_VTS, - imx219->mode->height + ctrl->val, &ret); + format->height + ctrl->val, &ret); break; case V4L2_CID_TEST_PATTERN_RED: cci_write(imx219->regmap, IMX219_REG_TESTP_RED, -- GitLab From e3e5d172d5fce9151bc101427554a158d4759856 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 24 Sep 2023 18:33:01 +0300 Subject: [PATCH 0484/1451] media: i2c: imx219: Don't store the current mode in the imx219 structure The mode field of the imx219 structure is only used in imx219_init_controls(), after the probe function sets it to point to the default mode. Use the default mode directly when initializing controls, and drop the mode field from the imx219 structure. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index f4f684bda4fab..82e5d1dad14a7 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -362,9 +362,6 @@ struct imx219 { struct v4l2_ctrl *vblank; struct v4l2_ctrl *hblank; - /* Current mode */ - const struct imx219_mode *mode; - /* Two or Four lanes */ u8 lanes; }; @@ -580,7 +577,6 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, *crop = mode->crop; if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - imx219->mode = mode; /* Update limits and set FPS to default */ __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN, IMX219_VTS_MAX - mode->height, 1, @@ -923,8 +919,8 @@ static unsigned long imx219_get_pixel_rate(struct imx219 *imx219) static int imx219_init_controls(struct imx219 *imx219) { struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); + const struct imx219_mode *mode = &supported_modes[0]; struct v4l2_ctrl_handler *ctrl_hdlr; - unsigned int height = imx219->mode->height; struct v4l2_fwnode_device_properties props; int exposure_max, exposure_def, hblank; int i, ret; @@ -953,15 +949,15 @@ static int imx219_init_controls(struct imx219 *imx219) /* Initial vblank/hblank/exposure parameters based on current mode */ imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_VBLANK, IMX219_VBLANK_MIN, - IMX219_VTS_MAX - height, 1, - imx219->mode->vts_def - height); - hblank = IMX219_PPL_DEFAULT - imx219->mode->width; + IMX219_VTS_MAX - mode->height, 1, + mode->vts_def - mode->height); + hblank = IMX219_PPL_DEFAULT - mode->width; imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_HBLANK, hblank, hblank, 1, hblank); if (imx219->hblank) imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; - exposure_max = imx219->mode->vts_def - 4; + exposure_max = mode->vts_def - 4; exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? exposure_max : IMX219_EXPOSURE_DEFAULT; imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, @@ -1148,10 +1144,8 @@ static int imx219_probe(struct i2c_client *client) if (ret) goto error_power_off; - /* Set default mode to max resolution */ - imx219->mode = &supported_modes[0]; - - /* sensor doesn't enter LP-11 state upon power up until and unless + /* + * Sensor doesn't enter LP-11 state upon power up until and unless * streaming is started, so upon power up switch the modes to: * streaming -> standby */ -- GitLab From 5ebbdd7aab3321e60a8be23aac1fee4f16644021 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 24 Sep 2023 18:33:02 +0300 Subject: [PATCH 0485/1451] media: i2c: imx219: Drop IMX219_VTS_* macros The IMX219_VTS_* macros define default VTS values for the modes supported by the driver. They are used in a single place, and hinder readability compared to using the value directly as a decimal number. Drop them. Signed-off-by: Laurent Pinchart Reviewed-by: Dave Stevenson Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 82e5d1dad14a7..76551e6db22ae 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -71,10 +71,6 @@ /* V_TIMING internal */ #define IMX219_REG_VTS CCI_REG16(0x0160) -#define IMX219_VTS_15FPS 0x0dc6 -#define IMX219_VTS_30FPS_1080P 0x06e3 -#define IMX219_VTS_30FPS_BINNED 0x06e3 -#define IMX219_VTS_30FPS_640x480 0x06e3 #define IMX219_VTS_MAX 0xffff #define IMX219_VBLANK_MIN 4 @@ -301,7 +297,7 @@ static const struct imx219_mode supported_modes[] = { .width = 3280, .height = 2464 }, - .vts_def = IMX219_VTS_15FPS, + .vts_def = 3526, }, { /* 1080P 30fps cropped */ @@ -313,7 +309,7 @@ static const struct imx219_mode supported_modes[] = { .width = 1920, .height = 1080 }, - .vts_def = IMX219_VTS_30FPS_1080P, + .vts_def = 1763, }, { /* 2x2 binned 30fps mode */ @@ -325,7 +321,7 @@ static const struct imx219_mode supported_modes[] = { .width = 3280, .height = 2464 }, - .vts_def = IMX219_VTS_30FPS_BINNED, + .vts_def = 1763, }, { /* 640x480 30fps mode */ @@ -337,7 +333,7 @@ static const struct imx219_mode supported_modes[] = { .width = 1280, .height = 960 }, - .vts_def = IMX219_VTS_30FPS_640x480, + .vts_def = 1763, }, }; -- GitLab From d03dfb7d4c5fae0d3f297536063e00ea2c1129d5 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 24 Sep 2023 18:33:03 +0300 Subject: [PATCH 0486/1451] media: i2c: imx219: Group functions by purpose Move functions around to group them by purpose, in order to improve readability. No functional change is intended. Signed-off-by: Laurent Pinchart Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 591 +++++++++++++++++++------------------ 1 file changed, 303 insertions(+), 288 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 76551e6db22ae..dfc5ce5742276 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -385,6 +385,10 @@ static u32 imx219_get_format_code(struct imx219 *imx219, u32 code) return imx219_mbus_formats[i]; } +/* ----------------------------------------------------------------------------- + * Controls + */ + static int imx219_set_ctrl(struct v4l2_ctrl *ctrl) { struct imx219 *imx219 = @@ -476,130 +480,135 @@ static const struct v4l2_ctrl_ops imx219_ctrl_ops = { .s_ctrl = imx219_set_ctrl, }; -static void imx219_update_pad_format(struct imx219 *imx219, - const struct imx219_mode *mode, - struct v4l2_mbus_framefmt *fmt, u32 code) +static unsigned long imx219_get_pixel_rate(struct imx219 *imx219) { - /* Bayer order varies with flips */ - fmt->code = imx219_get_format_code(imx219, code); - fmt->width = mode->width; - fmt->height = mode->height; - fmt->field = V4L2_FIELD_NONE; - fmt->colorspace = V4L2_COLORSPACE_RAW; - fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; - fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; - fmt->xfer_func = V4L2_XFER_FUNC_NONE; + return (imx219->lanes == 2) ? IMX219_PIXEL_RATE : IMX219_PIXEL_RATE_4LANE; } -static int imx219_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) +/* Initialize control handlers */ +static int imx219_init_controls(struct imx219 *imx219) { - struct imx219 *imx219 = to_imx219(sd); - struct v4l2_mbus_framefmt *format; - struct v4l2_rect *crop; - - /* Initialize the format. */ - format = v4l2_subdev_get_pad_format(sd, state, 0); - imx219_update_pad_format(imx219, &supported_modes[0], format, - MEDIA_BUS_FMT_SRGGB10_1X10); - - /* Initialize the crop rectangle. */ - crop = v4l2_subdev_get_pad_crop(sd, state, 0); - crop->top = IMX219_PIXEL_ARRAY_TOP; - crop->left = IMX219_PIXEL_ARRAY_LEFT; - crop->width = IMX219_PIXEL_ARRAY_WIDTH; - crop->height = IMX219_PIXEL_ARRAY_HEIGHT; + struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); + const struct imx219_mode *mode = &supported_modes[0]; + struct v4l2_ctrl_handler *ctrl_hdlr; + struct v4l2_fwnode_device_properties props; + int exposure_max, exposure_def, hblank; + int i, ret; - return 0; -} + ctrl_hdlr = &imx219->ctrl_handler; + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 12); + if (ret) + return ret; -static int imx219_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct imx219 *imx219 = to_imx219(sd); + /* By default, PIXEL_RATE is read only */ + imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, + V4L2_CID_PIXEL_RATE, + imx219_get_pixel_rate(imx219), + imx219_get_pixel_rate(imx219), 1, + imx219_get_pixel_rate(imx219)); - if (code->index >= (ARRAY_SIZE(imx219_mbus_formats) / 4)) - return -EINVAL; + imx219->link_freq = + v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx219_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(imx219_link_freq_menu) - 1, 0, + (imx219->lanes == 2) ? imx219_link_freq_menu : + imx219_link_freq_4lane_menu); + if (imx219->link_freq) + imx219->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; - code->code = imx219_get_format_code(imx219, imx219_mbus_formats[code->index * 4]); + /* Initial vblank/hblank/exposure parameters based on current mode */ + imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, + V4L2_CID_VBLANK, IMX219_VBLANK_MIN, + IMX219_VTS_MAX - mode->height, 1, + mode->vts_def - mode->height); + hblank = IMX219_PPL_DEFAULT - mode->width; + imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, + V4L2_CID_HBLANK, hblank, hblank, + 1, hblank); + if (imx219->hblank) + imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + exposure_max = mode->vts_def - 4; + exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? + exposure_max : IMX219_EXPOSURE_DEFAULT; + imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, + V4L2_CID_EXPOSURE, + IMX219_EXPOSURE_MIN, exposure_max, + IMX219_EXPOSURE_STEP, + exposure_def); - return 0; -} + v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX, + IMX219_ANA_GAIN_STEP, IMX219_ANA_GAIN_DEFAULT); -static int imx219_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct imx219 *imx219 = to_imx219(sd); - u32 code; + v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_DIGITAL_GAIN, + IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX, + IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT); - if (fse->index >= ARRAY_SIZE(supported_modes)) - return -EINVAL; + imx219->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + if (imx219->hflip) + imx219->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; - code = imx219_get_format_code(imx219, fse->code); - if (fse->code != code) - return -EINVAL; + imx219->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + if (imx219->vflip) + imx219->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; - fse->min_width = supported_modes[fse->index].width; - fse->max_width = fse->min_width; - fse->min_height = supported_modes[fse->index].height; - fse->max_height = fse->min_height; + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(imx219_test_pattern_menu) - 1, + 0, 0, imx219_test_pattern_menu); + for (i = 0; i < 4; i++) { + /* + * The assumption is that + * V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1 + * V4L2_CID_TEST_PATTERN_BLUE == V4L2_CID_TEST_PATTERN_RED + 2 + * V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3 + */ + v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, + V4L2_CID_TEST_PATTERN_RED + i, + IMX219_TESTP_COLOUR_MIN, + IMX219_TESTP_COLOUR_MAX, + IMX219_TESTP_COLOUR_STEP, + IMX219_TESTP_COLOUR_MAX); + /* The "Solid color" pattern is white by default */ + } - return 0; -} + if (ctrl_hdlr->error) { + ret = ctrl_hdlr->error; + dev_err(&client->dev, "%s control init failed (%d)\n", + __func__, ret); + goto error; + } -static int imx219_set_pad_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct imx219 *imx219 = to_imx219(sd); - const struct imx219_mode *mode; - int exposure_max, exposure_def, hblank; - struct v4l2_mbus_framefmt *format; - struct v4l2_rect *crop; + ret = v4l2_fwnode_device_parse(&client->dev, &props); + if (ret) + goto error; - mode = v4l2_find_nearest_size(supported_modes, - ARRAY_SIZE(supported_modes), - width, height, - fmt->format.width, fmt->format.height); + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx219_ctrl_ops, + &props); + if (ret) + goto error; - imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code); + imx219->sd.ctrl_handler = ctrl_hdlr; - format = v4l2_subdev_get_pad_format(sd, sd_state, 0); - crop = v4l2_subdev_get_pad_crop(sd, sd_state, 0); + return 0; - *format = fmt->format; - *crop = mode->crop; +error: + v4l2_ctrl_handler_free(ctrl_hdlr); - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - /* Update limits and set FPS to default */ - __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN, - IMX219_VTS_MAX - mode->height, 1, - mode->vts_def - mode->height); - __v4l2_ctrl_s_ctrl(imx219->vblank, - mode->vts_def - mode->height); - /* Update max exposure while meeting expected vblanking */ - exposure_max = mode->vts_def - 4; - exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? - exposure_max : IMX219_EXPOSURE_DEFAULT; - __v4l2_ctrl_modify_range(imx219->exposure, - imx219->exposure->minimum, - exposure_max, imx219->exposure->step, - exposure_def); - /* - * Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank - * depends on mode->width only, and is not changeble in any - * way other than changing the mode. - */ - hblank = IMX219_PPL_DEFAULT - mode->width; - __v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1, - hblank); - } + return ret; +} - return 0; +static void imx219_free_controls(struct imx219 *imx219) +{ + v4l2_ctrl_handler_free(imx219->sd.ctrl_handler); } +/* ----------------------------------------------------------------------------- + * Subdev operations + */ + static int imx219_set_framefmt(struct imx219 *imx219, struct v4l2_subdev_state *state) { @@ -664,37 +673,6 @@ static int imx219_set_framefmt(struct imx219 *imx219, return ret; } -static int imx219_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_selection *sel) -{ - switch (sel->target) { - case V4L2_SEL_TGT_CROP: { - sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, 0); - return 0; - } - - case V4L2_SEL_TGT_NATIVE_SIZE: - sel->r.top = 0; - sel->r.left = 0; - sel->r.width = IMX219_NATIVE_WIDTH; - sel->r.height = IMX219_NATIVE_HEIGHT; - - return 0; - - case V4L2_SEL_TGT_CROP_DEFAULT: - case V4L2_SEL_TGT_CROP_BOUNDS: - sel->r.top = IMX219_PIXEL_ARRAY_TOP; - sel->r.left = IMX219_PIXEL_ARRAY_LEFT; - sel->r.width = IMX219_PIXEL_ARRAY_WIDTH; - sel->r.height = IMX219_PIXEL_ARRAY_HEIGHT; - - return 0; - } - - return -EINVAL; -} - static int imx219_configure_lanes(struct imx219 *imx219) { return cci_write(imx219->regmap, IMX219_REG_CSI_LANE_MODE, @@ -799,86 +777,159 @@ static int imx219_set_stream(struct v4l2_subdev *sd, int enable) return ret; } -/* Power/clock management functions */ -static int imx219_power_on(struct device *dev) +static void imx219_update_pad_format(struct imx219 *imx219, + const struct imx219_mode *mode, + struct v4l2_mbus_framefmt *fmt, u32 code) { - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx219 *imx219 = to_imx219(sd); - int ret; + /* Bayer order varies with flips */ + fmt->code = imx219_get_format_code(imx219, code); + fmt->width = mode->width; + fmt->height = mode->height; + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_RAW; + fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; + fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + fmt->xfer_func = V4L2_XFER_FUNC_NONE; +} - ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES, - imx219->supplies); - if (ret) { - dev_err(dev, "%s: failed to enable regulators\n", - __func__); - return ret; - } +static int imx219_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct imx219 *imx219 = to_imx219(sd); + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; - ret = clk_prepare_enable(imx219->xclk); - if (ret) { - dev_err(dev, "%s: failed to enable clock\n", - __func__); - goto reg_off; - } + /* Initialize the format. */ + format = v4l2_subdev_get_pad_format(sd, state, 0); + imx219_update_pad_format(imx219, &supported_modes[0], format, + MEDIA_BUS_FMT_SRGGB10_1X10); - gpiod_set_value_cansleep(imx219->reset_gpio, 1); - usleep_range(IMX219_XCLR_MIN_DELAY_US, - IMX219_XCLR_MIN_DELAY_US + IMX219_XCLR_DELAY_RANGE_US); + /* Initialize the crop rectangle. */ + crop = v4l2_subdev_get_pad_crop(sd, state, 0); + crop->top = IMX219_PIXEL_ARRAY_TOP; + crop->left = IMX219_PIXEL_ARRAY_LEFT; + crop->width = IMX219_PIXEL_ARRAY_WIDTH; + crop->height = IMX219_PIXEL_ARRAY_HEIGHT; return 0; +} -reg_off: - regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies); +static int imx219_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct imx219 *imx219 = to_imx219(sd); - return ret; + if (code->index >= (ARRAY_SIZE(imx219_mbus_formats) / 4)) + return -EINVAL; + + code->code = imx219_get_format_code(imx219, imx219_mbus_formats[code->index * 4]); + + return 0; } -static int imx219_power_off(struct device *dev) +static int imx219_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) { - struct v4l2_subdev *sd = dev_get_drvdata(dev); struct imx219 *imx219 = to_imx219(sd); + u32 code; - gpiod_set_value_cansleep(imx219->reset_gpio, 0); - regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies); - clk_disable_unprepare(imx219->xclk); + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + code = imx219_get_format_code(imx219, fse->code); + if (fse->code != code) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = supported_modes[fse->index].height; + fse->max_height = fse->min_height; return 0; } -static int imx219_get_regulators(struct imx219 *imx219) +static int imx219_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) { - struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); - unsigned int i; + struct imx219 *imx219 = to_imx219(sd); + const struct imx219_mode *mode; + int exposure_max, exposure_def, hblank; + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; - for (i = 0; i < IMX219_NUM_SUPPLIES; i++) - imx219->supplies[i].supply = imx219_supply_name[i]; + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), + width, height, + fmt->format.width, fmt->format.height); - return devm_regulator_bulk_get(&client->dev, - IMX219_NUM_SUPPLIES, - imx219->supplies); + imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code); + + format = v4l2_subdev_get_pad_format(sd, sd_state, 0); + crop = v4l2_subdev_get_pad_crop(sd, sd_state, 0); + + *format = fmt->format; + *crop = mode->crop; + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + /* Update limits and set FPS to default */ + __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN, + IMX219_VTS_MAX - mode->height, 1, + mode->vts_def - mode->height); + __v4l2_ctrl_s_ctrl(imx219->vblank, + mode->vts_def - mode->height); + /* Update max exposure while meeting expected vblanking */ + exposure_max = mode->vts_def - 4; + exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? + exposure_max : IMX219_EXPOSURE_DEFAULT; + __v4l2_ctrl_modify_range(imx219->exposure, + imx219->exposure->minimum, + exposure_max, imx219->exposure->step, + exposure_def); + /* + * Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank + * depends on mode->width only, and is not changeble in any + * way other than changing the mode. + */ + hblank = IMX219_PPL_DEFAULT - mode->width; + __v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1, + hblank); + } + + return 0; } -/* Verify chip ID */ -static int imx219_identify_module(struct imx219 *imx219) +static int imx219_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) { - struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); - int ret; - u64 val; - - ret = cci_read(imx219->regmap, IMX219_REG_CHIP_ID, &val, NULL); - if (ret) { - dev_err(&client->dev, "failed to read chip id %x\n", - IMX219_CHIP_ID); - return ret; + switch (sel->target) { + case V4L2_SEL_TGT_CROP: { + sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, 0); + return 0; } - if (val != IMX219_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%llx\n", - IMX219_CHIP_ID, val); - return -EIO; + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = IMX219_NATIVE_WIDTH; + sel->r.height = IMX219_NATIVE_HEIGHT; + + return 0; + + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.top = IMX219_PIXEL_ARRAY_TOP; + sel->r.left = IMX219_PIXEL_ARRAY_LEFT; + sel->r.width = IMX219_PIXEL_ARRAY_WIDTH; + sel->r.height = IMX219_PIXEL_ARRAY_HEIGHT; + + return 0; } - return 0; + return -EINVAL; } static const struct v4l2_subdev_core_ops imx219_core_ops = { @@ -906,129 +957,93 @@ static const struct v4l2_subdev_ops imx219_subdev_ops = { }; -static unsigned long imx219_get_pixel_rate(struct imx219 *imx219) -{ - return (imx219->lanes == 2) ? IMX219_PIXEL_RATE : IMX219_PIXEL_RATE_4LANE; -} +/* ----------------------------------------------------------------------------- + * Power management + */ -/* Initialize control handlers */ -static int imx219_init_controls(struct imx219 *imx219) +static int imx219_power_on(struct device *dev) { - struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); - const struct imx219_mode *mode = &supported_modes[0]; - struct v4l2_ctrl_handler *ctrl_hdlr; - struct v4l2_fwnode_device_properties props; - int exposure_max, exposure_def, hblank; - int i, ret; + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx219 *imx219 = to_imx219(sd); + int ret; - ctrl_hdlr = &imx219->ctrl_handler; - ret = v4l2_ctrl_handler_init(ctrl_hdlr, 12); - if (ret) + ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES, + imx219->supplies); + if (ret) { + dev_err(dev, "%s: failed to enable regulators\n", + __func__); return ret; + } - /* By default, PIXEL_RATE is read only */ - imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, - V4L2_CID_PIXEL_RATE, - imx219_get_pixel_rate(imx219), - imx219_get_pixel_rate(imx219), 1, - imx219_get_pixel_rate(imx219)); + ret = clk_prepare_enable(imx219->xclk); + if (ret) { + dev_err(dev, "%s: failed to enable clock\n", + __func__); + goto reg_off; + } - imx219->link_freq = - v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx219_ctrl_ops, - V4L2_CID_LINK_FREQ, - ARRAY_SIZE(imx219_link_freq_menu) - 1, 0, - (imx219->lanes == 2) ? imx219_link_freq_menu : - imx219_link_freq_4lane_menu); - if (imx219->link_freq) - imx219->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + gpiod_set_value_cansleep(imx219->reset_gpio, 1); + usleep_range(IMX219_XCLR_MIN_DELAY_US, + IMX219_XCLR_MIN_DELAY_US + IMX219_XCLR_DELAY_RANGE_US); - /* Initial vblank/hblank/exposure parameters based on current mode */ - imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, - V4L2_CID_VBLANK, IMX219_VBLANK_MIN, - IMX219_VTS_MAX - mode->height, 1, - mode->vts_def - mode->height); - hblank = IMX219_PPL_DEFAULT - mode->width; - imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, - V4L2_CID_HBLANK, hblank, hblank, - 1, hblank); - if (imx219->hblank) - imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; - exposure_max = mode->vts_def - 4; - exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? - exposure_max : IMX219_EXPOSURE_DEFAULT; - imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, - V4L2_CID_EXPOSURE, - IMX219_EXPOSURE_MIN, exposure_max, - IMX219_EXPOSURE_STEP, - exposure_def); + return 0; - v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, - IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX, - IMX219_ANA_GAIN_STEP, IMX219_ANA_GAIN_DEFAULT); +reg_off: + regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies); - v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_DIGITAL_GAIN, - IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX, - IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT); + return ret; +} - imx219->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); - if (imx219->hflip) - imx219->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; +static int imx219_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx219 *imx219 = to_imx219(sd); - imx219->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); - if (imx219->vflip) - imx219->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + gpiod_set_value_cansleep(imx219->reset_gpio, 0); + regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies); + clk_disable_unprepare(imx219->xclk); - v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops, - V4L2_CID_TEST_PATTERN, - ARRAY_SIZE(imx219_test_pattern_menu) - 1, - 0, 0, imx219_test_pattern_menu); - for (i = 0; i < 4; i++) { - /* - * The assumption is that - * V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1 - * V4L2_CID_TEST_PATTERN_BLUE == V4L2_CID_TEST_PATTERN_RED + 2 - * V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3 - */ - v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, - V4L2_CID_TEST_PATTERN_RED + i, - IMX219_TESTP_COLOUR_MIN, - IMX219_TESTP_COLOUR_MAX, - IMX219_TESTP_COLOUR_STEP, - IMX219_TESTP_COLOUR_MAX); - /* The "Solid color" pattern is white by default */ - } + return 0; +} - if (ctrl_hdlr->error) { - ret = ctrl_hdlr->error; - dev_err(&client->dev, "%s control init failed (%d)\n", - __func__, ret); - goto error; - } +/* ----------------------------------------------------------------------------- + * Probe & remove + */ - ret = v4l2_fwnode_device_parse(&client->dev, &props); - if (ret) - goto error; +static int imx219_get_regulators(struct imx219 *imx219) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); + unsigned int i; - ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx219_ctrl_ops, - &props); - if (ret) - goto error; + for (i = 0; i < IMX219_NUM_SUPPLIES; i++) + imx219->supplies[i].supply = imx219_supply_name[i]; - imx219->sd.ctrl_handler = ctrl_hdlr; + return devm_regulator_bulk_get(&client->dev, + IMX219_NUM_SUPPLIES, + imx219->supplies); +} - return 0; +/* Verify chip ID */ +static int imx219_identify_module(struct imx219 *imx219) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); + int ret; + u64 val; -error: - v4l2_ctrl_handler_free(ctrl_hdlr); + ret = cci_read(imx219->regmap, IMX219_REG_CHIP_ID, &val, NULL); + if (ret) { + dev_err(&client->dev, "failed to read chip id %x\n", + IMX219_CHIP_ID); + return ret; + } - return ret; -} + if (val != IMX219_CHIP_ID) { + dev_err(&client->dev, "chip id mismatch: %x!=%llx\n", + IMX219_CHIP_ID, val); + return -EIO; + } -static void imx219_free_controls(struct imx219 *imx219) -{ - v4l2_ctrl_handler_free(imx219->sd.ctrl_handler); + return 0; } static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219) -- GitLab From d83b40ef9c078d0173dbdb8587ee220a185b5f80 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 24 Sep 2023 18:33:04 +0300 Subject: [PATCH 0487/1451] media: i2c: imx219: Remove unneeded goto Simplify the imx219_set_stream() by removing an unneeded goto statement, and its corresponding error label. The natural flow of the function is correct. While at it, drop a useless comment. Signed-off-by: Laurent Pinchart Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index dfc5ce5742276..a12ebf288dd2c 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -760,19 +760,11 @@ static int imx219_set_stream(struct v4l2_subdev *sd, int enable) state = v4l2_subdev_lock_and_get_active_state(sd); - if (enable) { - /* - * Apply default & customized values - * and then start streaming. - */ + if (enable) ret = imx219_start_streaming(imx219, state); - if (ret) - goto unlock; - } else { + else imx219_stop_streaming(imx219); - } -unlock: v4l2_subdev_unlock_state(state); return ret; } -- GitLab From eef9c161d029ed08bff2bdbf8bcc4ae9e731be3f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 24 Sep 2023 18:33:05 +0300 Subject: [PATCH 0488/1451] media: i2c: imx219: Implement .init_cfg() using .set_fmt() Instead of duplicating the logical implemented in the .set_fmt() operation in .init_cfg(), call .set_fmt() directly. This centralizes the format and crop rectangle calculations in a single place. Signed-off-by: Laurent Pinchart Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 40 +++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index a12ebf288dd2c..6bfdceaf5044e 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -784,28 +784,6 @@ static void imx219_update_pad_format(struct imx219 *imx219, fmt->xfer_func = V4L2_XFER_FUNC_NONE; } -static int imx219_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) -{ - struct imx219 *imx219 = to_imx219(sd); - struct v4l2_mbus_framefmt *format; - struct v4l2_rect *crop; - - /* Initialize the format. */ - format = v4l2_subdev_get_pad_format(sd, state, 0); - imx219_update_pad_format(imx219, &supported_modes[0], format, - MEDIA_BUS_FMT_SRGGB10_1X10); - - /* Initialize the crop rectangle. */ - crop = v4l2_subdev_get_pad_crop(sd, state, 0); - crop->top = IMX219_PIXEL_ARRAY_TOP; - crop->left = IMX219_PIXEL_ARRAY_LEFT; - crop->width = IMX219_PIXEL_ARRAY_WIDTH; - crop->height = IMX219_PIXEL_ARRAY_HEIGHT; - - return 0; -} - static int imx219_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) @@ -924,6 +902,24 @@ static int imx219_get_selection(struct v4l2_subdev *sd, return -EINVAL; } +static int imx219_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_TRY, + .pad = 0, + .format = { + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .width = supported_modes[0].width, + .height = supported_modes[0].height, + }, + }; + + imx219_set_pad_format(sd, state, &fmt); + + return 0; +} + static const struct v4l2_subdev_core_ops imx219_core_ops = { .subscribe_event = v4l2_ctrl_subdev_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, -- GitLab From 186aa9d472897bc5113eeb69c7ff6ed57c2263ee Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 24 Sep 2023 18:33:06 +0300 Subject: [PATCH 0489/1451] media: i2c: imx219: Separate horizontal and vertical binning The IMX219 has distinct binning registers for the horizontal and vertical directions. Calculate their value and write them separately. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 39 ++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 6bfdceaf5044e..bf1c2a1dad958 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -90,10 +90,11 @@ #define IMX219_REG_ORIENTATION CCI_REG8(0x0172) /* Binning Mode */ -#define IMX219_REG_BINNING_MODE CCI_REG16(0x0174) -#define IMX219_BINNING_NONE 0x0000 -#define IMX219_BINNING_2X2 0x0101 -#define IMX219_BINNING_2X2_ANALOG 0x0303 +#define IMX219_REG_BINNING_MODE_H CCI_REG8(0x0174) +#define IMX219_REG_BINNING_MODE_V CCI_REG8(0x0175) +#define IMX219_BINNING_NONE 0x00 +#define IMX219_BINNING_X2 0x01 +#define IMX219_BINNING_X2_ANALOG 0x03 #define IMX219_REG_CSI_DATA_FORMAT_A CCI_REG16(0x018c) @@ -615,7 +616,7 @@ static int imx219_set_framefmt(struct imx219 *imx219, const struct v4l2_mbus_framefmt *format; const struct v4l2_rect *crop; unsigned int bpp; - u64 bin_mode; + u64 bin_h, bin_v; int ret = 0; format = v4l2_subdev_get_pad_format(&imx219->sd, state, 0); @@ -647,14 +648,28 @@ static int imx219_set_framefmt(struct imx219 *imx219, cci_write(imx219->regmap, IMX219_REG_Y_ADD_END_A, crop->top - IMX219_PIXEL_ARRAY_TOP + crop->height - 1, &ret); - if (format->width == crop->width && format->height == crop->height) - bin_mode = IMX219_BINNING_NONE; - else if (bpp == 8) - bin_mode = IMX219_BINNING_2X2_ANALOG; - else - bin_mode = IMX219_BINNING_2X2; + switch (crop->width / format->width) { + case 1: + default: + bin_h = IMX219_BINNING_NONE; + break; + case 2: + bin_h = bpp == 8 ? IMX219_BINNING_X2_ANALOG : IMX219_BINNING_X2; + break; + } + + switch (crop->height / format->height) { + case 1: + default: + bin_v = IMX219_BINNING_NONE; + break; + case 2: + bin_v = bpp == 8 ? IMX219_BINNING_X2_ANALOG : IMX219_BINNING_X2; + break; + } - cci_write(imx219->regmap, IMX219_REG_BINNING_MODE, bin_mode, &ret); + cci_write(imx219->regmap, IMX219_REG_BINNING_MODE_H, bin_h, &ret); + cci_write(imx219->regmap, IMX219_REG_BINNING_MODE_V, bin_v, &ret); cci_write(imx219->regmap, IMX219_REG_X_OUTPUT_SIZE, format->width, &ret); -- GitLab From 0af46fbc333d1a52c72823d935590410357bab47 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 24 Sep 2023 18:33:07 +0300 Subject: [PATCH 0490/1451] media: i2c: imx219: Calculate crop rectangle dynamically Calculate the crop rectangle size and location dynamically when setting the format, instead of storing it in the imx219_mode structure. This removes duplicated information from the mode, to guarantee consistency. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 45 +++++++++++++------------------------- 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index bf1c2a1dad958..2b88c5b8a7bf3 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -153,9 +154,6 @@ struct imx219_mode { /* Frame height */ unsigned int height; - /* Analog crop rectangle. */ - struct v4l2_rect crop; - /* V-timing */ unsigned int vts_def; }; @@ -292,48 +290,24 @@ static const struct imx219_mode supported_modes[] = { /* 8MPix 15fps mode */ .width = 3280, .height = 2464, - .crop = { - .left = IMX219_PIXEL_ARRAY_LEFT, - .top = IMX219_PIXEL_ARRAY_TOP, - .width = 3280, - .height = 2464 - }, .vts_def = 3526, }, { /* 1080P 30fps cropped */ .width = 1920, .height = 1080, - .crop = { - .left = 688, - .top = 700, - .width = 1920, - .height = 1080 - }, .vts_def = 1763, }, { /* 2x2 binned 30fps mode */ .width = 1640, .height = 1232, - .crop = { - .left = IMX219_PIXEL_ARRAY_LEFT, - .top = IMX219_PIXEL_ARRAY_TOP, - .width = 3280, - .height = 2464 - }, .vts_def = 1763, }, { /* 640x480 30fps mode */ .width = 640, .height = 480, - .crop = { - .left = 1008, - .top = 760, - .width = 1280, - .height = 960 - }, .vts_def = 1763, }, }; @@ -844,6 +818,7 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, int exposure_max, exposure_def, hblank; struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; + unsigned int bin_h, bin_v; mode = v4l2_find_nearest_size(supported_modes, ARRAY_SIZE(supported_modes), @@ -853,10 +828,20 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code); format = v4l2_subdev_get_pad_format(sd, sd_state, 0); - crop = v4l2_subdev_get_pad_crop(sd, sd_state, 0); - *format = fmt->format; - *crop = mode->crop; + + /* + * Use binning to maximize the crop rectangle size, and centre it in the + * sensor. + */ + bin_h = min(IMX219_PIXEL_ARRAY_WIDTH / format->width, 2U); + bin_v = min(IMX219_PIXEL_ARRAY_HEIGHT / format->height, 2U); + + crop = v4l2_subdev_get_pad_crop(sd, sd_state, 0); + crop->width = format->width * bin_h; + crop->height = format->height * bin_v; + crop->left = (IMX219_NATIVE_WIDTH - crop->width) / 2; + crop->top = (IMX219_NATIVE_HEIGHT - crop->height) / 2; if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Update limits and set FPS to default */ -- GitLab From bf313f998f7445dda5969bbd57321721b754e760 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 24 Sep 2023 18:33:08 +0300 Subject: [PATCH 0491/1451] media: i2c: imx219: Name all subdev state variables 'state' Subdev state variables are named with a mix of 'state' and 'sd_state' through the driver. To improve consistency, name them all 'state'. Signed-off-by: Laurent Pinchart Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 2b88c5b8a7bf3..358a6d77d88cf 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -774,7 +774,7 @@ static void imx219_update_pad_format(struct imx219 *imx219, } static int imx219_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_state *state, struct v4l2_subdev_mbus_code_enum *code) { struct imx219 *imx219 = to_imx219(sd); @@ -788,7 +788,7 @@ static int imx219_enum_mbus_code(struct v4l2_subdev *sd, } static int imx219_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_state *state, struct v4l2_subdev_frame_size_enum *fse) { struct imx219 *imx219 = to_imx219(sd); @@ -810,7 +810,7 @@ static int imx219_enum_frame_size(struct v4l2_subdev *sd, } static int imx219_set_pad_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_state *state, struct v4l2_subdev_format *fmt) { struct imx219 *imx219 = to_imx219(sd); @@ -827,7 +827,7 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code); - format = v4l2_subdev_get_pad_format(sd, sd_state, 0); + format = v4l2_subdev_get_pad_format(sd, state, 0); *format = fmt->format; /* @@ -837,7 +837,7 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, bin_h = min(IMX219_PIXEL_ARRAY_WIDTH / format->width, 2U); bin_v = min(IMX219_PIXEL_ARRAY_HEIGHT / format->height, 2U); - crop = v4l2_subdev_get_pad_crop(sd, sd_state, 0); + crop = v4l2_subdev_get_pad_crop(sd, state, 0); crop->width = format->width * bin_h; crop->height = format->height * bin_v; crop->left = (IMX219_NATIVE_WIDTH - crop->width) / 2; @@ -872,12 +872,12 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, } static int imx219_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_state *state, struct v4l2_subdev_selection *sel) { switch (sel->target) { case V4L2_SEL_TGT_CROP: { - sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, 0); + sel->r = *v4l2_subdev_get_pad_crop(sd, state, 0); return 0; } -- GitLab From ef202378ccdd23a7af99607d6ecb857212793824 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 24 Sep 2023 18:33:09 +0300 Subject: [PATCH 0492/1451] media: i2c: imx219: Move variables to inner scope The exposure_max, exposure_def and hblank variables are only used in an inner scope in the imx219_set_pad_format() function. Move them to that scope to keep them closer to their usage and improve readability. Signed-off-by: Laurent Pinchart Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/imx219.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 358a6d77d88cf..8436880dcf7a8 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -815,7 +815,6 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, { struct imx219 *imx219 = to_imx219(sd); const struct imx219_mode *mode; - int exposure_max, exposure_def, hblank; struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; unsigned int bin_h, bin_v; @@ -844,6 +843,10 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, crop->top = (IMX219_NATIVE_HEIGHT - crop->height) / 2; if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + int exposure_max; + int exposure_def; + int hblank; + /* Update limits and set FPS to default */ __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN, IMX219_VTS_MAX - mode->height, 1, -- GitLab From 580139fa0c3025e39d55f9472bafbd8f0f662d7b Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 2 Aug 2023 15:11:50 +0300 Subject: [PATCH 0493/1451] media: Documentation: Align numbered list, make it a proper ReST Align lines for numbered list so that Sphinx produces an uniform output for all list entries. Also indent paragraphs of such list entries for consistency. Also use ReST numbered list syntax for the entries. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- .../userspace-api/media/v4l/dev-subdev.rst | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/dev-subdev.rst b/Documentation/userspace-api/media/v4l/dev-subdev.rst index a4f1df7093e8e..43988516acddf 100644 --- a/Documentation/userspace-api/media/v4l/dev-subdev.rst +++ b/Documentation/userspace-api/media/v4l/dev-subdev.rst @@ -579,20 +579,19 @@ is started. There are three steps in configuring the streams: -1) Set up links. Connect the pads between sub-devices using the :ref:`Media -Controller API ` +1. Set up links. Connect the pads between sub-devices using the + :ref:`Media Controller API ` -2) Streams. Streams are declared and their routing is configured by -setting the routing table for the sub-device using -:ref:`VIDIOC_SUBDEV_S_ROUTING ` ioctl. Note that -setting the routing table will reset formats and selections in the -sub-device to default values. +2. Streams. Streams are declared and their routing is configured by setting the + routing table for the sub-device using :ref:`VIDIOC_SUBDEV_S_ROUTING + ` ioctl. Note that setting the routing table will + reset formats and selections in the sub-device to default values. -3) Configure formats and selections. Formats and selections of each stream -are configured separately as documented for plain sub-devices in -:ref:`format-propagation`. The stream ID is set to the same stream ID -associated with either sink or source pads of routes configured using the -:ref:`VIDIOC_SUBDEV_S_ROUTING ` ioctl. +3. Configure formats and selections. Formats and selections of each stream are + configured separately as documented for plain sub-devices in + :ref:`format-propagation`. The stream ID is set to the same stream ID + associated with either sink or source pads of routes configured using the + :ref:`VIDIOC_SUBDEV_S_ROUTING ` ioctl. Multiplexed streams setup example ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -618,11 +617,11 @@ modeled as V4L2 devices, exposed to userspace via /dev/videoX nodes. To configure this pipeline, the userspace must take the following steps: -1) Set up media links between entities: connect the sensors to the bridge, -bridge to the receiver, and the receiver to the DMA engines. This step does -not differ from normal non-multiplexed media controller setup. +1. Set up media links between entities: connect the sensors to the bridge, + bridge to the receiver, and the receiver to the DMA engines. This step does + not differ from normal non-multiplexed media controller setup. -2) Configure routing +2. Configure routing .. flat-table:: Bridge routing table :header-rows: 1 @@ -656,14 +655,14 @@ not differ from normal non-multiplexed media controller setup. - V4L2_SUBDEV_ROUTE_FL_ACTIVE - Pixel data stream from Sensor B -3) Configure formats and selections +3. Configure formats and selections -After configuring routing, the next step is configuring the formats and -selections for the streams. This is similar to performing this step without -streams, with just one exception: the ``stream`` field needs to be assigned -to the value of the stream ID. + After configuring routing, the next step is configuring the formats and + selections for the streams. This is similar to performing this step without + streams, with just one exception: the ``stream`` field needs to be assigned + to the value of the stream ID. -A common way to accomplish this is to start from the sensors and propagate the -configurations along the stream towards the receiver, -using :ref:`VIDIOC_SUBDEV_S_FMT ` ioctls to configure each -stream endpoint in each sub-device. + A common way to accomplish this is to start from the sensors and propagate + the configurations along the stream towards the receiver, using + :ref:`VIDIOC_SUBDEV_S_FMT ` ioctls to configure each + stream endpoint in each sub-device. -- GitLab From 441b5c63d71ec9ec5453328f7e83384ecc1dddd9 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 24 Aug 2023 15:18:18 +0300 Subject: [PATCH 0494/1451] media: ccs: Fix driver quirk struct documentation Fix documentation for struct ccs_quirk, a device specific struct for managing deviations from the standard. The flags field was drifted away from where it should have been. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/i2c/ccs/ccs-quirk.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-quirk.h b/drivers/media/i2c/ccs/ccs-quirk.h index 5838fcda92fd4..0b1a64958d714 100644 --- a/drivers/media/i2c/ccs/ccs-quirk.h +++ b/drivers/media/i2c/ccs/ccs-quirk.h @@ -32,12 +32,10 @@ struct ccs_sensor; * @reg: Pointer to the register to access * @value: Register value, set by the caller on write, or * by the quirk on read - * - * @flags: Quirk flags - * * @return: 0 on success, -ENOIOCTLCMD if no register * access may be done by the caller (default read * value is zero), else negative error code on error + * @flags: Quirk flags */ struct ccs_quirk { int (*limits)(struct ccs_sensor *sensor); -- GitLab From 724ff68e968b19d786870d333f9952bdd6b119cb Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 4 Sep 2023 15:57:37 +0300 Subject: [PATCH 0495/1451] media: ccs: Correctly initialise try compose rectangle Initialise the try sink compose rectangle size to the sink compose rectangle for binner and scaler sub-devices. This was missed due to the faulty condition that lead to the compose rectangles to be initialised for the pixel array sub-device where it is not relevant. Fixes: ccfc97bdb5ae ("[media] smiapp: Add driver") Cc: stable@vger.kernel.org Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/i2c/ccs/ccs-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 6a8116454f877..022e8712d48e1 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -3097,7 +3097,7 @@ static int ccs_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) try_fmt->code = sensor->internal_csi_format->code; try_fmt->field = V4L2_FIELD_NONE; - if (ssd != sensor->pixel_array) + if (ssd == sensor->pixel_array) continue; try_comp = v4l2_subdev_get_try_compose(sd, fh->state, i); -- GitLab From f055e53ebcfc042e6a26acc27acac25ef9c0188e Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 23 Aug 2023 11:44:37 +0300 Subject: [PATCH 0496/1451] media: ccs: Correct error handling in ccs_register_subdev ccs_register_subdev() did not clean up the media entity in error case, do that now. Also switch to goto based error handling. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/i2c/ccs/ccs-core.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 022e8712d48e1..fb823c5c3dd31 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -2968,7 +2968,7 @@ static int ccs_register_subdev(struct ccs_sensor *sensor, rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev, &ssd->sd); if (rval) { dev_err(&client->dev, "v4l2_device_register_subdev failed\n"); - return rval; + goto out_media_entity_cleanup; } rval = media_create_pad_link(&ssd->sd.entity, source_pad, @@ -2976,11 +2976,18 @@ static int ccs_register_subdev(struct ccs_sensor *sensor, link_flags); if (rval) { dev_err(&client->dev, "media_create_pad_link failed\n"); - v4l2_device_unregister_subdev(&ssd->sd); - return rval; + goto out_v4l2_device_unregister_subdev; } return 0; + +out_v4l2_device_unregister_subdev: + v4l2_device_unregister_subdev(&ssd->sd); + +out_media_entity_cleanup: + media_entity_cleanup(&ssd->sd.entity); + + return rval; } static void ccs_unregistered(struct v4l2_subdev *subdev) -- GitLab From 3935665586783dffaafb8308f561b12800245af5 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 9 Aug 2023 16:12:38 +0300 Subject: [PATCH 0497/1451] media: ccs: Switch to init_cfg Use init_cfg() instead of manually setting up defaults in file handle open. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/i2c/ccs/ccs-core.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index fb823c5c3dd31..9e87696037047 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -2945,7 +2945,6 @@ static int ccs_identify_module(struct ccs_sensor *sensor) } static const struct v4l2_subdev_ops ccs_ops; -static const struct v4l2_subdev_internal_ops ccs_internal_ops; static const struct media_entity_operations ccs_entity_ops; static int ccs_register_subdev(struct ccs_sensor *sensor, @@ -3076,13 +3075,13 @@ static void ccs_create_subdev(struct ccs_sensor *sensor, if (ssd == sensor->src) return; - ssd->sd.internal_ops = &ccs_internal_ops; ssd->sd.owner = THIS_MODULE; ssd->sd.dev = &client->dev; v4l2_set_subdevdata(&ssd->sd, client); } -static int ccs_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +static int ccs_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct ccs_subdev *ssd = to_ccs_subdev(sd); struct ccs_sensor *sensor = ssd->sensor; @@ -3092,9 +3091,9 @@ static int ccs_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) for (i = 0; i < ssd->npads; i++) { struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(sd, fh->state, i); + v4l2_subdev_get_try_format(sd, sd_state, i); struct v4l2_rect *try_crop = - v4l2_subdev_get_try_crop(sd, fh->state, i); + v4l2_subdev_get_try_crop(sd, sd_state, i); struct v4l2_rect *try_comp; ccs_get_native_size(ssd, try_crop); @@ -3107,7 +3106,7 @@ static int ccs_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) if (ssd == sensor->pixel_array) continue; - try_comp = v4l2_subdev_get_try_compose(sd, fh->state, i); + try_comp = v4l2_subdev_get_try_compose(sd, sd_state, i); *try_comp = *try_crop; } @@ -3123,6 +3122,7 @@ static const struct v4l2_subdev_video_ops ccs_video_ops = { }; static const struct v4l2_subdev_pad_ops ccs_pad_ops = { + .init_cfg = ccs_init_cfg, .enum_mbus_code = ccs_enum_mbus_code, .get_fmt = ccs_get_format, .set_fmt = ccs_set_format, @@ -3148,11 +3148,6 @@ static const struct media_entity_operations ccs_entity_ops = { static const struct v4l2_subdev_internal_ops ccs_internal_src_ops = { .registered = ccs_registered, .unregistered = ccs_unregistered, - .open = ccs_open, -}; - -static const struct v4l2_subdev_internal_ops ccs_internal_ops = { - .open = ccs_open, }; /* ----------------------------------------------------------------------------- -- GitLab From ac84b72242ce745ccf79df1504a53afd079e5b45 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 2 Oct 2023 10:19:15 +0300 Subject: [PATCH 0498/1451] media: ccs: Rename ccs_create_subdev as ccs_init_subdev The ccs_create_subdev() function initialises a sub-device in the CCS driver, including CCS specific needs. Rename it as ccs_init_subdev() as it better reflects what the function does. Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ccs/ccs-core.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 9e87696037047..6bcce908f93b0 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -3038,9 +3038,9 @@ static void ccs_cleanup(struct ccs_sensor *sensor) ccs_free_controls(sensor); } -static void ccs_create_subdev(struct ccs_sensor *sensor, - struct ccs_subdev *ssd, const char *name, - unsigned short num_pads, u32 function) +static void ccs_init_subdev(struct ccs_sensor *sensor, + struct ccs_subdev *ssd, const char *name, + unsigned short num_pads, u32 function) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); @@ -3553,12 +3553,12 @@ static int ccs_probe(struct i2c_client *client) sensor->pll.ext_clk_freq_hz = sensor->hwcfg.ext_clk; sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); - ccs_create_subdev(sensor, sensor->scaler, " scaler", 2, - MEDIA_ENT_F_PROC_VIDEO_SCALER); - ccs_create_subdev(sensor, sensor->binner, " binner", 2, - MEDIA_ENT_F_PROC_VIDEO_SCALER); - ccs_create_subdev(sensor, sensor->pixel_array, " pixel_array", 1, - MEDIA_ENT_F_CAM_SENSOR); + ccs_init_subdev(sensor, sensor->scaler, " scaler", 2, + MEDIA_ENT_F_PROC_VIDEO_SCALER); + ccs_init_subdev(sensor, sensor->binner, " binner", 2, + MEDIA_ENT_F_PROC_VIDEO_SCALER); + ccs_init_subdev(sensor, sensor->pixel_array, " pixel_array", 1, + MEDIA_ENT_F_CAM_SENSOR); rval = ccs_init_controls(sensor); if (rval < 0) -- GitLab From 77ab9dc8d926bf5a0ce1f6dde14c0bb29c473426 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 2 Oct 2023 10:25:37 +0300 Subject: [PATCH 0499/1451] media: ccs: Move media_entity_pads_init to init from register The media entity will soon need to be initialised before the sub-device init finalisation that allocates memory for sub-device state. Do that now. Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ccs/ccs-core.c | 75 +++++++++++++++----------------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 6bcce908f93b0..e2669e9299ab4 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -2958,16 +2958,10 @@ static int ccs_register_subdev(struct ccs_sensor *sensor, if (!sink_ssd) return 0; - rval = media_entity_pads_init(&ssd->sd.entity, ssd->npads, ssd->pads); - if (rval) { - dev_err(&client->dev, "media_entity_pads_init failed\n"); - return rval; - } - rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev, &ssd->sd); if (rval) { dev_err(&client->dev, "v4l2_device_register_subdev failed\n"); - goto out_media_entity_cleanup; + return rval; } rval = media_create_pad_link(&ssd->sd.entity, source_pad, @@ -2975,18 +2969,11 @@ static int ccs_register_subdev(struct ccs_sensor *sensor, link_flags); if (rval) { dev_err(&client->dev, "media_create_pad_link failed\n"); - goto out_v4l2_device_unregister_subdev; + v4l2_device_unregister_subdev(&ssd->sd); + return rval; } return 0; - -out_v4l2_device_unregister_subdev: - v4l2_device_unregister_subdev(&ssd->sd); - -out_media_entity_cleanup: - media_entity_cleanup(&ssd->sd.entity); - - return rval; } static void ccs_unregistered(struct v4l2_subdev *subdev) @@ -3031,6 +3018,10 @@ static int ccs_registered(struct v4l2_subdev *subdev) static void ccs_cleanup(struct ccs_sensor *sensor) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + unsigned int i; + + for (i = 0; i < sensor->ssds_used; i++) + media_entity_cleanup(&sensor->ssds[i].sd.entity); device_remove_file(&client->dev, &dev_attr_nvm); device_remove_file(&client->dev, &dev_attr_ident); @@ -3038,14 +3029,15 @@ static void ccs_cleanup(struct ccs_sensor *sensor) ccs_free_controls(sensor); } -static void ccs_init_subdev(struct ccs_sensor *sensor, - struct ccs_subdev *ssd, const char *name, - unsigned short num_pads, u32 function) +static int ccs_init_subdev(struct ccs_sensor *sensor, + struct ccs_subdev *ssd, const char *name, + unsigned short num_pads, u32 function) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; if (!ssd) - return; + return 0; if (ssd != sensor->src) v4l2_subdev_init(&ssd->sd, &ccs_ops); @@ -3072,12 +3064,20 @@ static void ccs_init_subdev(struct ccs_sensor *sensor, ssd->sd.entity.ops = &ccs_entity_ops; + rval = media_entity_pads_init(&ssd->sd.entity, ssd->npads, ssd->pads); + if (rval) { + dev_err(&client->dev, "media_entity_pads_init failed\n"); + return rval; + } + if (ssd == sensor->src) - return; + return 0; ssd->sd.owner = THIS_MODULE; ssd->sd.dev = &client->dev; v4l2_set_subdevdata(&ssd->sd, client); + + return 0; } static int ccs_init_cfg(struct v4l2_subdev *sd, @@ -3553,12 +3553,18 @@ static int ccs_probe(struct i2c_client *client) sensor->pll.ext_clk_freq_hz = sensor->hwcfg.ext_clk; sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); - ccs_init_subdev(sensor, sensor->scaler, " scaler", 2, - MEDIA_ENT_F_PROC_VIDEO_SCALER); - ccs_init_subdev(sensor, sensor->binner, " binner", 2, - MEDIA_ENT_F_PROC_VIDEO_SCALER); - ccs_init_subdev(sensor, sensor->pixel_array, " pixel_array", 1, - MEDIA_ENT_F_CAM_SENSOR); + rval = ccs_init_subdev(sensor, sensor->scaler, " scaler", 2, + MEDIA_ENT_F_PROC_VIDEO_SCALER); + if (rval) + goto out_cleanup; + rval = ccs_init_subdev(sensor, sensor->binner, " binner", 2, + MEDIA_ENT_F_PROC_VIDEO_SCALER); + if (rval) + goto out_cleanup; + rval = ccs_init_subdev(sensor, sensor->pixel_array, " pixel_array", 1, + MEDIA_ENT_F_CAM_SENSOR); + if (rval) + goto out_cleanup; rval = ccs_init_controls(sensor); if (rval < 0) @@ -3591,14 +3597,9 @@ static int ccs_probe(struct i2c_client *client) sensor->streaming = false; sensor->dev_init_done = true; - rval = media_entity_pads_init(&sensor->src->sd.entity, 2, - sensor->src->pads); - if (rval < 0) - goto out_media_entity_cleanup; - rval = ccs_write_msr_regs(sensor); if (rval) - goto out_media_entity_cleanup; + goto out_cleanup; pm_runtime_set_active(&client->dev); pm_runtime_get_noresume(&client->dev); @@ -3618,9 +3619,6 @@ static int ccs_probe(struct i2c_client *client) pm_runtime_put_noidle(&client->dev); pm_runtime_disable(&client->dev); -out_media_entity_cleanup: - media_entity_cleanup(&sensor->src->sd.entity); - out_cleanup: ccs_cleanup(sensor); @@ -3653,10 +3651,9 @@ static void ccs_remove(struct i2c_client *client) ccs_power_off(&client->dev); pm_runtime_set_suspended(&client->dev); - for (i = 0; i < sensor->ssds_used; i++) { + for (i = 0; i < sensor->ssds_used; i++) v4l2_device_unregister_subdev(&sensor->ssds[i].sd); - media_entity_cleanup(&sensor->ssds[i].sd.entity); - } + ccs_cleanup(sensor); mutex_destroy(&sensor->mutex); kfree(sensor->ccs_limits); -- GitLab From f00a1572b65a444082fb72488ae3b7ce73065696 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 2 Oct 2023 13:29:22 +0300 Subject: [PATCH 0500/1451] media: ccs: Obtain media bus formats before initialising up sub-devices The available mbus codes will soon be needed earlier, at the time sub-devices are initialisaed. This is due to calling init_cfg() op via the v4l2_subdev_init_finalize(). Move ccs_get_mbus_formats() before ccs_init_subdev() calls. Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ccs/ccs-core.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index e2669e9299ab4..422fb6a4a9072 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -3553,6 +3553,12 @@ static int ccs_probe(struct i2c_client *client) sensor->pll.ext_clk_freq_hz = sensor->hwcfg.ext_clk; sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); + rval = ccs_get_mbus_formats(sensor); + if (rval) { + rval = -ENODEV; + goto out_cleanup; + } + rval = ccs_init_subdev(sensor, sensor->scaler, " scaler", 2, MEDIA_ENT_F_PROC_VIDEO_SCALER); if (rval) @@ -3574,12 +3580,6 @@ static int ccs_probe(struct i2c_client *client) if (rval) goto out_cleanup; - rval = ccs_get_mbus_formats(sensor); - if (rval) { - rval = -ENODEV; - goto out_cleanup; - } - rval = ccs_init_late_controls(sensor); if (rval) { rval = -ENODEV; -- GitLab From d8bca3ed1d70652e68b07799171d471026b7b3e2 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 24 Aug 2023 10:31:10 +0300 Subject: [PATCH 0501/1451] media: ccs: Use sub-device active state Make use of sub-device active state. In most cases the effect on need for acquiring the mutex is non-existent as access to the driver's core data structure still needs to be serialised. This still removes a lot of code as the code paths for active and try state are the same in many cases. Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ccs/ccs-core.c | 286 +++++++++++-------------------- drivers/media/i2c/ccs/ccs.h | 4 +- 2 files changed, 104 insertions(+), 186 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 422fb6a4a9072..c6853622946bc 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -508,9 +508,8 @@ static void __ccs_update_exposure_limits(struct ccs_sensor *sensor) struct v4l2_ctrl *ctrl = sensor->exposure; int max; - max = sensor->pixel_array->crop[CCS_PA_PAD_SRC].height - + sensor->vblank->val - - CCS_LIM(sensor, COARSE_INTEGRATION_TIME_MAX_MARGIN); + max = sensor->pa_src.height + sensor->vblank->val - + CCS_LIM(sensor, COARSE_INTEGRATION_TIME_MAX_MARGIN); __v4l2_ctrl_modify_range(ctrl, ctrl->minimum, max, ctrl->step, max); } @@ -728,15 +727,12 @@ static int ccs_set_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_VBLANK: rval = ccs_write(sensor, FRAME_LENGTH_LINES, - sensor->pixel_array->crop[ - CCS_PA_PAD_SRC].height - + ctrl->val); + sensor->pa_src.height + ctrl->val); break; case V4L2_CID_HBLANK: rval = ccs_write(sensor, LINE_LENGTH_PCK, - sensor->pixel_array->crop[CCS_PA_PAD_SRC].width - + ctrl->val); + sensor->pa_src.width + ctrl->val); break; case V4L2_CID_TEST_PATTERN: @@ -1214,15 +1210,13 @@ static void ccs_update_blanking(struct ccs_sensor *sensor) min = max_t(int, CCS_LIM(sensor, MIN_FRAME_BLANKING_LINES), - min_fll - sensor->pixel_array->crop[CCS_PA_PAD_SRC].height); - max = max_fll - sensor->pixel_array->crop[CCS_PA_PAD_SRC].height; + min_fll - sensor->pa_src.height); + max = max_fll - sensor->pa_src.height; __v4l2_ctrl_modify_range(vblank, min, max, vblank->step, min); - min = max_t(int, - min_llp - sensor->pixel_array->crop[CCS_PA_PAD_SRC].width, - min_lbp); - max = max_llp - sensor->pixel_array->crop[CCS_PA_PAD_SRC].width; + min = max_t(int, min_llp - sensor->pa_src.width, min_lbp); + max = max_llp - sensor->pa_src.width; __v4l2_ctrl_modify_range(hblank, min, max, hblank->step, min); @@ -1246,10 +1240,8 @@ static int ccs_pll_blanking_update(struct ccs_sensor *sensor) dev_dbg(&client->dev, "real timeperframe\t100/%d\n", sensor->pll.pixel_rate_pixel_array / - ((sensor->pixel_array->crop[CCS_PA_PAD_SRC].width - + sensor->hblank->val) * - (sensor->pixel_array->crop[CCS_PA_PAD_SRC].height - + sensor->vblank->val) / 100)); + ((sensor->pa_src.width + sensor->hblank->val) * + (sensor->pa_src.height + sensor->vblank->val) / 100)); return 0; } @@ -1756,28 +1748,22 @@ static int ccs_start_streaming(struct ccs_sensor *sensor) goto out; /* Analog crop start coordinates */ - rval = ccs_write(sensor, X_ADDR_START, - sensor->pixel_array->crop[CCS_PA_PAD_SRC].left); + rval = ccs_write(sensor, X_ADDR_START, sensor->pa_src.left); if (rval < 0) goto out; - rval = ccs_write(sensor, Y_ADDR_START, - sensor->pixel_array->crop[CCS_PA_PAD_SRC].top); + rval = ccs_write(sensor, Y_ADDR_START, sensor->pa_src.top); if (rval < 0) goto out; /* Analog crop end coordinates */ - rval = ccs_write( - sensor, X_ADDR_END, - sensor->pixel_array->crop[CCS_PA_PAD_SRC].left - + sensor->pixel_array->crop[CCS_PA_PAD_SRC].width - 1); + rval = ccs_write(sensor, X_ADDR_END, + sensor->pa_src.left + sensor->pa_src.width - 1); if (rval < 0) goto out; - rval = ccs_write( - sensor, Y_ADDR_END, - sensor->pixel_array->crop[CCS_PA_PAD_SRC].top - + sensor->pixel_array->crop[CCS_PA_PAD_SRC].height - 1); + rval = ccs_write(sensor, Y_ADDR_END, + sensor->pa_src.top + sensor->pa_src.height - 1); if (rval < 0) goto out; @@ -1789,27 +1775,23 @@ static int ccs_start_streaming(struct ccs_sensor *sensor) /* Digital crop */ if (CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) == CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { - rval = ccs_write( - sensor, DIGITAL_CROP_X_OFFSET, - sensor->scaler->crop[CCS_PAD_SINK].left); + rval = ccs_write(sensor, DIGITAL_CROP_X_OFFSET, + sensor->scaler_sink.left); if (rval < 0) goto out; - rval = ccs_write( - sensor, DIGITAL_CROP_Y_OFFSET, - sensor->scaler->crop[CCS_PAD_SINK].top); + rval = ccs_write(sensor, DIGITAL_CROP_Y_OFFSET, + sensor->scaler_sink.top); if (rval < 0) goto out; - rval = ccs_write( - sensor, DIGITAL_CROP_IMAGE_WIDTH, - sensor->scaler->crop[CCS_PAD_SINK].width); + rval = ccs_write(sensor, DIGITAL_CROP_IMAGE_WIDTH, + sensor->scaler_sink.width); if (rval < 0) goto out; - rval = ccs_write( - sensor, DIGITAL_CROP_IMAGE_HEIGHT, - sensor->scaler->crop[CCS_PAD_SINK].height); + rval = ccs_write(sensor, DIGITAL_CROP_IMAGE_HEIGHT, + sensor->scaler_sink.height); if (rval < 0) goto out; } @@ -1827,12 +1809,10 @@ static int ccs_start_streaming(struct ccs_sensor *sensor) } /* Output size from sensor */ - rval = ccs_write(sensor, X_OUTPUT_SIZE, - sensor->src->crop[CCS_PAD_SRC].width); + rval = ccs_write(sensor, X_OUTPUT_SIZE, sensor->src_src.width); if (rval < 0) goto out; - rval = ccs_write(sensor, Y_OUTPUT_SIZE, - sensor->src->crop[CCS_PAD_SRC].height); + rval = ccs_write(sensor, Y_OUTPUT_SIZE, sensor->src_src.height); if (rval < 0) goto out; @@ -2053,24 +2033,8 @@ static int __ccs_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { - struct ccs_subdev *ssd = to_ccs_subdev(subdev); - - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - fmt->format = *v4l2_subdev_get_try_format(subdev, sd_state, - fmt->pad); - } else { - struct v4l2_rect *r; - - if (fmt->pad == ssd->source_pad) - r = &ssd->crop[ssd->source_pad]; - else - r = &ssd->sink_fmt; - - fmt->format.code = __ccs_get_mbus_code(subdev, fmt->pad); - fmt->format.width = r->width; - fmt->format.height = r->height; - fmt->format.field = V4L2_FIELD_NONE; - } + fmt->format = *v4l2_subdev_get_pad_format(subdev, sd_state, fmt->pad); + fmt->format.code = __ccs_get_mbus_code(subdev, fmt->pad); return 0; } @@ -2092,28 +2056,18 @@ static int ccs_get_format(struct v4l2_subdev *subdev, static void ccs_get_crop_compose(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state, struct v4l2_rect **crops, - struct v4l2_rect **comps, int which) + struct v4l2_rect **comps) { struct ccs_subdev *ssd = to_ccs_subdev(subdev); unsigned int i; - if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { - if (crops) - for (i = 0; i < subdev->entity.num_pads; i++) - crops[i] = &ssd->crop[i]; - if (comps) - *comps = &ssd->compose; - } else { - if (crops) { - for (i = 0; i < subdev->entity.num_pads; i++) - crops[i] = v4l2_subdev_get_try_crop(subdev, - sd_state, - i); - } - if (comps) - *comps = v4l2_subdev_get_try_compose(subdev, sd_state, - CCS_PAD_SINK); - } + if (crops) + for (i = 0; i < subdev->entity.num_pads; i++) + crops[i] = + v4l2_subdev_get_pad_crop(subdev, sd_state, i); + if (comps) + *comps = v4l2_subdev_get_pad_compose(subdev, sd_state, + ssd->sink_pad); } /* Changes require propagation only on sink pad. */ @@ -2125,7 +2079,7 @@ static void ccs_propagate(struct v4l2_subdev *subdev, struct ccs_subdev *ssd = to_ccs_subdev(subdev); struct v4l2_rect *comp, *crops[CCS_PADS]; - ccs_get_crop_compose(subdev, sd_state, crops, &comp, which); + ccs_get_crop_compose(subdev, sd_state, crops, &comp); switch (target) { case V4L2_SEL_TGT_CROP: @@ -2136,6 +2090,7 @@ static void ccs_propagate(struct v4l2_subdev *subdev, sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN); sensor->scaling_mode = CCS_SCALING_MODE_NO_SCALING; + sensor->scaler_sink = *comp; } else if (ssd == sensor->binner) { sensor->binning_horizontal = 1; sensor->binning_vertical = 1; @@ -2144,6 +2099,8 @@ static void ccs_propagate(struct v4l2_subdev *subdev, fallthrough; case V4L2_SEL_TGT_COMPOSE: *crops[CCS_PAD_SRC] = *comp; + if (which == V4L2_SUBDEV_FORMAT_ACTIVE && ssd == sensor->src) + sensor->src_src = *crops[CCS_PAD_SRC]; break; default: WARN_ON_ONCE(1); @@ -2252,14 +2209,12 @@ static int ccs_set_format(struct v4l2_subdev *subdev, CCS_LIM(sensor, MIN_Y_OUTPUT_SIZE), CCS_LIM(sensor, MAX_Y_OUTPUT_SIZE)); - ccs_get_crop_compose(subdev, sd_state, crops, NULL, fmt->which); + ccs_get_crop_compose(subdev, sd_state, crops, NULL); crops[ssd->sink_pad]->left = 0; crops[ssd->sink_pad]->top = 0; crops[ssd->sink_pad]->width = fmt->format.width; crops[ssd->sink_pad]->height = fmt->format.height; - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) - ssd->sink_fmt = *crops[ssd->sink_pad]; ccs_propagate(subdev, sd_state, fmt->which, V4L2_SEL_TGT_CROP); mutex_unlock(&sensor->mutex); @@ -2482,7 +2437,7 @@ static int ccs_set_compose(struct v4l2_subdev *subdev, struct ccs_subdev *ssd = to_ccs_subdev(subdev); struct v4l2_rect *comp, *crops[CCS_PADS]; - ccs_get_crop_compose(subdev, sd_state, crops, &comp, sel->which); + ccs_get_crop_compose(subdev, sd_state, crops, &comp); sel->r.top = 0; sel->r.left = 0; @@ -2501,8 +2456,8 @@ static int ccs_set_compose(struct v4l2_subdev *subdev, return 0; } -static int __ccs_sel_supported(struct v4l2_subdev *subdev, - struct v4l2_subdev_selection *sel) +static int ccs_sel_supported(struct v4l2_subdev *subdev, + struct v4l2_subdev_selection *sel) { struct ccs_sensor *sensor = to_ccs_sensor(subdev); struct ccs_subdev *ssd = to_ccs_subdev(subdev); @@ -2545,33 +2500,18 @@ static int ccs_set_crop(struct v4l2_subdev *subdev, { struct ccs_sensor *sensor = to_ccs_sensor(subdev); struct ccs_subdev *ssd = to_ccs_subdev(subdev); - struct v4l2_rect *src_size, *crops[CCS_PADS]; - struct v4l2_rect _r; + struct v4l2_rect src_size = { 0 }, *crops[CCS_PADS], *comp; - ccs_get_crop_compose(subdev, sd_state, crops, NULL, sel->which); + ccs_get_crop_compose(subdev, sd_state, crops, &comp); - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - if (sel->pad == ssd->sink_pad) - src_size = &ssd->sink_fmt; - else - src_size = &ssd->compose; + if (sel->pad == ssd->sink_pad) { + struct v4l2_mbus_framefmt *mfmt = + v4l2_subdev_get_pad_format(subdev, sd_state, sel->pad); + + src_size.width = mfmt->width; + src_size.height = mfmt->height; } else { - if (sel->pad == ssd->sink_pad) { - _r.left = 0; - _r.top = 0; - _r.width = v4l2_subdev_get_try_format(subdev, - sd_state, - sel->pad) - ->width; - _r.height = v4l2_subdev_get_try_format(subdev, - sd_state, - sel->pad) - ->height; - src_size = &_r; - } else { - src_size = v4l2_subdev_get_try_compose( - subdev, sd_state, ssd->sink_pad); - } + src_size = *comp; } if (ssd == sensor->src && sel->pad == CCS_PAD_SRC) { @@ -2579,16 +2519,19 @@ static int ccs_set_crop(struct v4l2_subdev *subdev, sel->r.top = 0; } - sel->r.width = min(sel->r.width, src_size->width); - sel->r.height = min(sel->r.height, src_size->height); + sel->r.width = min(sel->r.width, src_size.width); + sel->r.height = min(sel->r.height, src_size.height); - sel->r.left = min_t(int, sel->r.left, src_size->width - sel->r.width); - sel->r.top = min_t(int, sel->r.top, src_size->height - sel->r.height); + sel->r.left = min_t(int, sel->r.left, src_size.width - sel->r.width); + sel->r.top = min_t(int, sel->r.top, src_size.height - sel->r.height); *crops[sel->pad] = sel->r; if (ssd != sensor->pixel_array && sel->pad == CCS_PAD_SINK) ccs_propagate(subdev, sd_state, sel->which, V4L2_SEL_TGT_CROP); + else if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE && + ssd == sensor->pixel_array) + sensor->pa_src = sel->r; return 0; } @@ -2601,44 +2544,36 @@ static void ccs_get_native_size(struct ccs_subdev *ssd, struct v4l2_rect *r) r->height = CCS_LIM(ssd->sensor, Y_ADDR_MAX) + 1; } -static int __ccs_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_selection *sel) +static int ccs_get_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) { struct ccs_sensor *sensor = to_ccs_sensor(subdev); struct ccs_subdev *ssd = to_ccs_subdev(subdev); struct v4l2_rect *comp, *crops[CCS_PADS]; - struct v4l2_rect sink_fmt; int ret; - ret = __ccs_sel_supported(subdev, sel); + ret = ccs_sel_supported(subdev, sel); if (ret) return ret; - ccs_get_crop_compose(subdev, sd_state, crops, &comp, sel->which); - - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - sink_fmt = ssd->sink_fmt; - } else { - struct v4l2_mbus_framefmt *fmt = - v4l2_subdev_get_try_format(subdev, sd_state, - ssd->sink_pad); - - sink_fmt.left = 0; - sink_fmt.top = 0; - sink_fmt.width = fmt->width; - sink_fmt.height = fmt->height; - } + ccs_get_crop_compose(subdev, sd_state, crops, &comp); switch (sel->target) { case V4L2_SEL_TGT_CROP_BOUNDS: case V4L2_SEL_TGT_NATIVE_SIZE: - if (ssd == sensor->pixel_array) + if (ssd == sensor->pixel_array) { ccs_get_native_size(ssd, &sel->r); - else if (sel->pad == ssd->sink_pad) - sel->r = sink_fmt; - else + } else if (sel->pad == ssd->sink_pad) { + struct v4l2_mbus_framefmt *sink_fmt = + v4l2_subdev_get_pad_format(subdev, sd_state, + ssd->sink_pad); + sel->r.top = sel->r.left = 0; + sel->r.width = sink_fmt->width; + sel->r.height = sink_fmt->height; + } else { sel->r = *comp; + } break; case V4L2_SEL_TGT_CROP: case V4L2_SEL_TGT_COMPOSE_BOUNDS: @@ -2652,20 +2587,6 @@ static int __ccs_get_selection(struct v4l2_subdev *subdev, return 0; } -static int ccs_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_selection *sel) -{ - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - int rval; - - mutex_lock(&sensor->mutex); - rval = __ccs_get_selection(subdev, sd_state, sel); - mutex_unlock(&sensor->mutex); - - return rval; -} - static int ccs_set_selection(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) @@ -2673,7 +2594,7 @@ static int ccs_set_selection(struct v4l2_subdev *subdev, struct ccs_sensor *sensor = to_ccs_sensor(subdev); int ret; - ret = __ccs_sel_supported(subdev, sel); + ret = ccs_sel_supported(subdev, sel); if (ret) return ret; @@ -3020,8 +2941,10 @@ static void ccs_cleanup(struct ccs_sensor *sensor) struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); unsigned int i; - for (i = 0; i < sensor->ssds_used; i++) + for (i = 0; i < sensor->ssds_used; i++) { + v4l2_subdev_cleanup(&sensor->ssds[2].sd); media_entity_cleanup(&sensor->ssds[i].sd.entity); + } device_remove_file(&client->dev, &dev_attr_nvm); device_remove_file(&client->dev, &dev_attr_ident); @@ -3051,31 +2974,29 @@ static int ccs_init_subdev(struct ccs_sensor *sensor, v4l2_i2c_subdev_set_name(&ssd->sd, client, sensor->minfo.name, name); - ccs_get_native_size(ssd, &ssd->sink_fmt); - - ssd->compose.width = ssd->sink_fmt.width; - ssd->compose.height = ssd->sink_fmt.height; - ssd->crop[ssd->source_pad] = ssd->compose; ssd->pads[ssd->source_pad].flags = MEDIA_PAD_FL_SOURCE; - if (ssd != sensor->pixel_array) { - ssd->crop[ssd->sink_pad] = ssd->compose; + if (ssd != sensor->pixel_array) ssd->pads[ssd->sink_pad].flags = MEDIA_PAD_FL_SINK; - } ssd->sd.entity.ops = &ccs_entity_ops; + if (ssd != sensor->src) { + ssd->sd.owner = THIS_MODULE; + ssd->sd.dev = &client->dev; + v4l2_set_subdevdata(&ssd->sd, client); + } + rval = media_entity_pads_init(&ssd->sd.entity, ssd->npads, ssd->pads); if (rval) { dev_err(&client->dev, "media_entity_pads_init failed\n"); return rval; } - if (ssd == sensor->src) - return 0; - - ssd->sd.owner = THIS_MODULE; - ssd->sd.dev = &client->dev; - v4l2_set_subdevdata(&ssd->sd, client); + rval = v4l2_subdev_init_finalize(&ssd->sd); + if (rval) { + media_entity_cleanup(&ssd->sd.entity); + return rval; + } return 0; } @@ -3090,24 +3011,24 @@ static int ccs_init_cfg(struct v4l2_subdev *sd, mutex_lock(&sensor->mutex); for (i = 0; i < ssd->npads; i++) { - struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(sd, sd_state, i); - struct v4l2_rect *try_crop = - v4l2_subdev_get_try_crop(sd, sd_state, i); - struct v4l2_rect *try_comp; + struct v4l2_mbus_framefmt *fmt = + v4l2_subdev_get_pad_format(sd, sd_state, i); + struct v4l2_rect *crop = + v4l2_subdev_get_pad_crop(sd, sd_state, i); + struct v4l2_rect *comp; - ccs_get_native_size(ssd, try_crop); + ccs_get_native_size(ssd, crop); - try_fmt->width = try_crop->width; - try_fmt->height = try_crop->height; - try_fmt->code = sensor->internal_csi_format->code; - try_fmt->field = V4L2_FIELD_NONE; + fmt->width = crop->width; + fmt->height = crop->height; + fmt->code = sensor->internal_csi_format->code; + fmt->field = V4L2_FIELD_NONE; if (ssd == sensor->pixel_array) continue; - try_comp = v4l2_subdev_get_try_compose(sd, sd_state, i); - *try_comp = *try_crop; + comp = v4l2_subdev_get_pad_compose(sd, sd_state, i); + *comp = *crop; } mutex_unlock(&sensor->mutex); @@ -3653,7 +3574,6 @@ static void ccs_remove(struct i2c_client *client) for (i = 0; i < sensor->ssds_used; i++) v4l2_device_unregister_subdev(&sensor->ssds[i].sd); - ccs_cleanup(sensor); mutex_destroy(&sensor->mutex); kfree(sensor->ccs_limits); diff --git a/drivers/media/i2c/ccs/ccs.h b/drivers/media/i2c/ccs/ccs.h index a94c796cea487..9c3587b2fbe73 100644 --- a/drivers/media/i2c/ccs/ccs.h +++ b/drivers/media/i2c/ccs/ccs.h @@ -182,9 +182,6 @@ struct ccs_binning_subtype { struct ccs_subdev { struct v4l2_subdev sd; struct media_pad pads[CCS_PADS]; - struct v4l2_rect sink_fmt; - struct v4l2_rect crop[CCS_PADS]; - struct v4l2_rect compose; /* compose on sink */ unsigned short sink_pad; unsigned short source_pad; int npads; @@ -220,6 +217,7 @@ struct ccs_sensor { u32 mbus_frame_fmts; const struct ccs_csi_data_format *csi_format; const struct ccs_csi_data_format *internal_csi_format; + struct v4l2_rect pa_src, scaler_sink, src_src; u32 default_mbus_frame_fmts; int default_pixel_order; struct ccs_data_container sdata, mdata; -- GitLab From 2428e585b1e79efc1ecc3eaf64ad777e1272b792 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 29 Sep 2023 12:00:42 +0300 Subject: [PATCH 0502/1451] media: ccs: Partially revert "media: i2c: Use pm_runtime_resume_and_get()" ccs_pm_get_init() depends on the return values > 0 of pm_runtime_get_sync(), thus it can't use pm_runtime_resume_and_get(). There's even a comment in the driver on this, a few lines above the code. Fixes: aa0adb399d09 ("media: i2c: Use pm_runtime_resume_and_get()") Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ccs/ccs-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index c6853622946bc..34f4f62a95239 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -1873,9 +1873,9 @@ static int ccs_pm_get_init(struct ccs_sensor *sensor) * relies at the returned value to detect if the device was already * active or not. */ - rval = pm_runtime_resume_and_get(&client->dev); - if (rval) - return rval; + rval = pm_runtime_get_sync(&client->dev); + if (rval < 0) + goto error; /* Device was already active, so don't set controls */ if (rval == 1) -- GitLab From 8a695a29d68e8f6e7334ae4fdcffd7e687a48d2f Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 29 Sep 2023 11:32:46 +0300 Subject: [PATCH 0503/1451] media: ccs: Drop re-entrant s_stream support The s_stream is called to enable and to disable streaming on a sub-device. The caller may only call it to change the state, enabling streaming is not allowed when it is already disabled, and similarly for disabling streaming. Remove the check from the CCS driver. Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ccs/ccs-core.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 34f4f62a95239..2abfd5932e027 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -1903,9 +1903,6 @@ static int ccs_set_stream(struct v4l2_subdev *subdev, int enable) struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); int rval; - if (sensor->streaming == enable) - return 0; - if (!enable) { ccs_stop_streaming(sensor); sensor->streaming = false; -- GitLab From 1cfe77a541a5044a061afd4f7935f504cc4d4c48 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 8 Sep 2023 11:52:12 +0300 Subject: [PATCH 0504/1451] media: ov2740: Enable runtime PM before registering the async subdev Enable runtime PM before registering the async subdev as the driver UAPI may become accessible immediately after the registration. Runtime PM needs to be enabled by that time. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov2740.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index 3a9700fbbe8cb..6d5fb2789dc6a 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -1130,6 +1130,12 @@ static int ov2740_probe(struct i2c_client *client) goto probe_error_v4l2_ctrl_handler_free; } + /* Set the device's state to active if it's in D0 state. */ + if (full_power) + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + pm_runtime_idle(&client->dev); + ret = v4l2_async_register_subdev_sensor(&ov2740->sd); if (ret < 0) { dev_err_probe(dev, ret, "failed to register V4L2 subdev\n"); @@ -1140,16 +1146,12 @@ static int ov2740_probe(struct i2c_client *client) if (ret) dev_warn(&client->dev, "register nvmem failed, ret %d\n", ret); - /* Set the device's state to active if it's in D0 state. */ - if (full_power) - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); - return 0; probe_error_media_entity_cleanup: media_entity_cleanup(&ov2740->sd.entity); + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); probe_error_v4l2_ctrl_handler_free: v4l2_ctrl_handler_free(ov2740->sd.ctrl_handler); -- GitLab From 289c25923ecdde90050a0cb3904f9295ca68b425 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 7 Sep 2023 15:10:03 +0300 Subject: [PATCH 0505/1451] media: ov2740: Use sub-device active state Use sub-device active state. Rely on control handler lock to serialise access to the active state. Also clean up locking on s_stream handler. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov2740.c | 109 ++++++++++++++----------------------- 1 file changed, 42 insertions(+), 67 deletions(-) diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index 6d5fb2789dc6a..d83ac31efd9cb 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -336,9 +336,6 @@ struct ov2740 { /* Current mode */ const struct ov2740_mode *cur_mode; - /* To serialize asynchronus callbacks */ - struct mutex mutex; - /* NVM data inforamtion */ struct nvm_data *nvm; @@ -579,7 +576,6 @@ static int ov2740_init_controls(struct ov2740 *ov2740) if (ret) return ret; - ctrl_hdlr->lock = &ov2740->mutex; cur_mode = ov2740->cur_mode; size = ARRAY_SIZE(link_freq_menu_items); @@ -789,15 +785,15 @@ static int ov2740_set_stream(struct v4l2_subdev *sd, int enable) { struct ov2740 *ov2740 = to_ov2740(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); + struct v4l2_subdev_state *sd_state; int ret = 0; - mutex_lock(&ov2740->mutex); + sd_state = v4l2_subdev_lock_and_get_active_state(&ov2740->sd); + if (enable) { ret = pm_runtime_resume_and_get(&client->dev); - if (ret < 0) { - mutex_unlock(&ov2740->mutex); - return ret; - } + if (ret < 0) + goto out_unlock; ret = ov2740_start_streaming(ov2740); if (ret) { @@ -810,7 +806,8 @@ static int ov2740_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - mutex_unlock(&ov2740->mutex); +out_unlock: + v4l2_subdev_unlock_state(sd_state); return ret; } @@ -828,48 +825,26 @@ static int ov2740_set_format(struct v4l2_subdev *sd, height, fmt->format.width, fmt->format.height); - mutex_lock(&ov2740->mutex); ov2740_update_pad_format(mode, &fmt->format); - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format; - } else { - ov2740->cur_mode = mode; - __v4l2_ctrl_s_ctrl(ov2740->link_freq, mode->link_freq_index); - __v4l2_ctrl_s_ctrl_int64(ov2740->pixel_rate, - to_pixel_rate(mode->link_freq_index)); - - /* Update limits and set FPS to default */ - vblank_def = mode->vts_def - mode->height; - __v4l2_ctrl_modify_range(ov2740->vblank, - mode->vts_min - mode->height, - OV2740_VTS_MAX - mode->height, 1, - vblank_def); - __v4l2_ctrl_s_ctrl(ov2740->vblank, vblank_def); - h_blank = to_pixels_per_line(mode->hts, mode->link_freq_index) - - mode->width; - __v4l2_ctrl_modify_range(ov2740->hblank, h_blank, h_blank, 1, - h_blank); - } - mutex_unlock(&ov2740->mutex); + *v4l2_subdev_get_pad_format(sd, sd_state, fmt->pad) = fmt->format; - return 0; -} - -static int ov2740_get_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct ov2740 *ov2740 = to_ov2740(sd); - - mutex_lock(&ov2740->mutex); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - fmt->format = *v4l2_subdev_get_try_format(&ov2740->sd, - sd_state, - fmt->pad); - else - ov2740_update_pad_format(ov2740->cur_mode, &fmt->format); + return 0; - mutex_unlock(&ov2740->mutex); + ov2740->cur_mode = mode; + __v4l2_ctrl_s_ctrl(ov2740->link_freq, mode->link_freq_index); + __v4l2_ctrl_s_ctrl_int64(ov2740->pixel_rate, + to_pixel_rate(mode->link_freq_index)); + + /* Update limits and set FPS to default */ + vblank_def = mode->vts_def - mode->height; + __v4l2_ctrl_modify_range(ov2740->vblank, + mode->vts_min - mode->height, + OV2740_VTS_MAX - mode->height, 1, vblank_def); + __v4l2_ctrl_s_ctrl(ov2740->vblank, vblank_def); + h_blank = to_pixels_per_line(mode->hts, mode->link_freq_index) - + mode->width; + __v4l2_ctrl_modify_range(ov2740->hblank, h_blank, h_blank, 1, h_blank); return 0; } @@ -904,14 +879,11 @@ static int ov2740_enum_frame_size(struct v4l2_subdev *sd, return 0; } -static int ov2740_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +static int ov2740_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { - struct ov2740 *ov2740 = to_ov2740(sd); - - mutex_lock(&ov2740->mutex); ov2740_update_pad_format(&supported_modes[0], - v4l2_subdev_get_try_format(sd, fh->state, 0)); - mutex_unlock(&ov2740->mutex); + v4l2_subdev_get_pad_format(sd, sd_state, 0)); return 0; } @@ -921,10 +893,11 @@ static const struct v4l2_subdev_video_ops ov2740_video_ops = { }; static const struct v4l2_subdev_pad_ops ov2740_pad_ops = { + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = ov2740_set_format, - .get_fmt = ov2740_get_format, .enum_mbus_code = ov2740_enum_mbus_code, .enum_frame_size = ov2740_enum_frame_size, + .init_cfg = ov2740_init_cfg, }; static const struct v4l2_subdev_ops ov2740_subdev_ops = { @@ -936,10 +909,6 @@ static const struct media_entity_operations ov2740_subdev_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; -static const struct v4l2_subdev_internal_ops ov2740_internal_ops = { - .open = ov2740_open, -}; - static int ov2740_check_hwcfg(struct device *dev) { struct fwnode_handle *ep; @@ -1005,13 +974,12 @@ static int ov2740_check_hwcfg(struct device *dev) static void ov2740_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov2740 *ov2740 = to_ov2740(sd); v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); + v4l2_subdev_cleanup(sd); v4l2_ctrl_handler_free(sd->ctrl_handler); pm_runtime_disable(&client->dev); - mutex_destroy(&ov2740->mutex); } static int ov2740_nvmem_read(void *priv, unsigned int off, void *val, @@ -1020,9 +988,11 @@ static int ov2740_nvmem_read(void *priv, unsigned int off, void *val, struct nvm_data *nvm = priv; struct device *dev = regmap_get_device(nvm->regmap); struct ov2740 *ov2740 = to_ov2740(dev_get_drvdata(dev)); + struct v4l2_subdev_state *sd_state; int ret = 0; - mutex_lock(&ov2740->mutex); + /* Serialise sensor access */ + sd_state = v4l2_subdev_lock_and_get_active_state(&ov2740->sd); if (nvm->nvm_buffer) { memcpy(val, nvm->nvm_buffer + off, count); @@ -1040,7 +1010,7 @@ static int ov2740_nvmem_read(void *priv, unsigned int off, void *val, pm_runtime_put(dev); exit: - mutex_unlock(&ov2740->mutex); + v4l2_subdev_unlock_state(sd_state); return ret; } @@ -1111,7 +1081,6 @@ static int ov2740_probe(struct i2c_client *client) return dev_err_probe(dev, ret, "failed to find sensor\n"); } - mutex_init(&ov2740->mutex); ov2740->cur_mode = &supported_modes[0]; ret = ov2740_init_controls(ov2740); if (ret) { @@ -1119,7 +1088,7 @@ static int ov2740_probe(struct i2c_client *client) goto probe_error_v4l2_ctrl_handler_free; } - ov2740->sd.internal_ops = &ov2740_internal_ops; + ov2740->sd.state_lock = ov2740->ctrl_handler.lock; ov2740->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ov2740->sd.entity.ops = &ov2740_subdev_entity_ops; ov2740->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; @@ -1130,6 +1099,10 @@ static int ov2740_probe(struct i2c_client *client) goto probe_error_v4l2_ctrl_handler_free; } + ret = v4l2_subdev_init_finalize(&ov2740->sd); + if (ret) + goto probe_error_media_entity_cleanup; + /* Set the device's state to active if it's in D0 state. */ if (full_power) pm_runtime_set_active(&client->dev); @@ -1139,7 +1112,7 @@ static int ov2740_probe(struct i2c_client *client) ret = v4l2_async_register_subdev_sensor(&ov2740->sd); if (ret < 0) { dev_err_probe(dev, ret, "failed to register V4L2 subdev\n"); - goto probe_error_media_entity_cleanup; + goto probe_error_v4l2_subdev_cleanup; } ret = ov2740_register_nvmem(client, ov2740); @@ -1148,6 +1121,9 @@ static int ov2740_probe(struct i2c_client *client) return 0; +probe_error_v4l2_subdev_cleanup: + v4l2_subdev_cleanup(&ov2740->sd); + probe_error_media_entity_cleanup: media_entity_cleanup(&ov2740->sd.entity); pm_runtime_disable(&client->dev); @@ -1155,7 +1131,6 @@ static int ov2740_probe(struct i2c_client *client) probe_error_v4l2_ctrl_handler_free: v4l2_ctrl_handler_free(ov2740->sd.ctrl_handler); - mutex_destroy(&ov2740->mutex); return ret; } -- GitLab From 07d81b507df5622db40104c64dace3387bbe23b9 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 8 Sep 2023 12:56:16 +0300 Subject: [PATCH 0506/1451] media: ov2740: Return -EPROBE_DEFER if no endpoint is found With ipu bridge, endpoints may only be created when ipu bridge has initialised. This may happen after the sensor driver has first probed. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/i2c/ov2740.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index d83ac31efd9cb..24e468485fbf0 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -931,7 +931,7 @@ static int ov2740_check_hwcfg(struct device *dev) ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) - return -ENXIO; + return -EPROBE_DEFER; ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); fwnode_handle_put(ep); -- GitLab From 76c0b99d614127ceadcd3563dee4983c20627e09 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 15 Sep 2023 14:23:28 +0300 Subject: [PATCH 0507/1451] media: v4l: subdev: Clear frame descriptor before get_frame_desc Clear frame descriptor before calling transmitter's get_frame_desc() op. Also remove the corresponding memset() calls from drivers. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Signed-off-by: Hans Verkuil --- drivers/media/i2c/ds90ub913.c | 2 -- drivers/media/i2c/ds90ub953.c | 2 -- drivers/media/i2c/ds90ub960.c | 2 -- drivers/media/platform/nxp/imx-mipi-csis.c | 2 -- drivers/media/v4l2-core/v4l2-subdev.c | 9 +++++++++ 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/media/i2c/ds90ub913.c b/drivers/media/i2c/ds90ub913.c index 4bfa3b3cf619b..8e9ebed09f649 100644 --- a/drivers/media/i2c/ds90ub913.c +++ b/drivers/media/i2c/ds90ub913.c @@ -362,8 +362,6 @@ static int ub913_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, if (ret) return ret; - memset(fd, 0, sizeof(*fd)); - fd->type = V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL; state = v4l2_subdev_lock_and_get_active_state(sd); diff --git a/drivers/media/i2c/ds90ub953.c b/drivers/media/i2c/ds90ub953.c index dc394e22a42c4..644022312833d 100644 --- a/drivers/media/i2c/ds90ub953.c +++ b/drivers/media/i2c/ds90ub953.c @@ -499,8 +499,6 @@ static int ub953_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, if (ret) return ret; - memset(fd, 0, sizeof(*fd)); - fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2; state = v4l2_subdev_lock_and_get_active_state(sd); diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c index 8ba5750f5a231..b8f3e5ca03efb 100644 --- a/drivers/media/i2c/ds90ub960.c +++ b/drivers/media/i2c/ds90ub960.c @@ -2786,8 +2786,6 @@ static int ub960_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, if (!ub960_pad_is_source(priv, pad)) return -EINVAL; - memset(fd, 0, sizeof(*fd)); - fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2; state = v4l2_subdev_lock_and_get_active_state(&priv->sd); diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index 5f93712bf4854..6cb20b45e0a13 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -1114,8 +1114,6 @@ static int mipi_csis_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, fd->type = V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL; fd->num_entries = 1; - memset(entry, 0, sizeof(*entry)); - entry->flags = 0; entry->pixelcode = csis_fmt->code; entry->bus.csi2.vc = 0; diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 32b7d9cd43e62..9cb04ace86ae6 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -306,6 +306,14 @@ static int call_set_selection(struct v4l2_subdev *sd, sd->ops->pad->set_selection(sd, state, sel); } +static int call_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + memset(fd, 0, sizeof(*fd)); + + return sd->ops->pad->get_frame_desc(sd, pad, fd); +} + static inline int check_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) { @@ -446,6 +454,7 @@ static const struct v4l2_subdev_pad_ops v4l2_subdev_call_pad_wrappers = { .set_edid = call_set_edid, .dv_timings_cap = call_dv_timings_cap, .enum_dv_timings = call_enum_dv_timings, + .get_frame_desc = call_get_frame_desc, .get_mbus_config = call_get_mbus_config, }; -- GitLab From 4c812e33b0de26bc61e2ab5b3c4dd3e4d3c6cd51 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 12 Sep 2023 14:55:24 +0300 Subject: [PATCH 0508/1451] media: v4l: subdev: Print debug information on frame descriptor Print debug level information on returned frame descriptors. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/v4l2-core/v4l2-subdev.c | 31 ++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 9cb04ace86ae6..d295a4e87b66d 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -309,9 +310,37 @@ static int call_set_selection(struct v4l2_subdev *sd, static int call_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_mbus_frame_desc *fd) { + unsigned int i; + int ret; + memset(fd, 0, sizeof(*fd)); - return sd->ops->pad->get_frame_desc(sd, pad, fd); + ret = sd->ops->pad->get_frame_desc(sd, pad, fd); + if (ret) + return ret; + + dev_dbg(sd->dev, "Frame descriptor on pad %u, type %s\n", pad, + fd->type == V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL ? "parallel" : + fd->type == V4L2_MBUS_FRAME_DESC_TYPE_CSI2 ? "CSI-2" : + "unknown"); + + for (i = 0; i < fd->num_entries; i++) { + struct v4l2_mbus_frame_desc_entry *entry = &fd->entry[i]; + char buf[20] = ""; + + if (fd->type == V4L2_MBUS_FRAME_DESC_TYPE_CSI2) + WARN_ON(snprintf(buf, sizeof(buf), + ", vc %u, dt 0x%02x", + entry->bus.csi2.vc, + entry->bus.csi2.dt) >= sizeof(buf)); + + dev_dbg(sd->dev, + "\tstream %u, code 0x%04x, length %u, flags 0x%04x%s\n", + entry->stream, entry->pixelcode, entry->length, + entry->flags, buf); + } + + return 0; } static inline int check_edid(struct v4l2_subdev *sd, -- GitLab From deb866f9e3a45ae058b21765feeffae6aea6a193 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 25 Apr 2023 12:30:45 +0300 Subject: [PATCH 0509/1451] media: mc: Check pad flag validity Check the validity of pad flags on entity init. Exactly one of the flags must be set. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/media/mc/mc-entity.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c index 83468d4a440b3..543a392f86357 100644 --- a/drivers/media/mc/mc-entity.c +++ b/drivers/media/mc/mc-entity.c @@ -197,6 +197,7 @@ int media_entity_pads_init(struct media_entity *entity, u16 num_pads, struct media_device *mdev = entity->graph_obj.mdev; struct media_pad *iter; unsigned int i = 0; + int ret = 0; if (num_pads >= MEDIA_ENTITY_MAX_PADS) return -E2BIG; @@ -210,15 +211,27 @@ int media_entity_pads_init(struct media_entity *entity, u16 num_pads, media_entity_for_each_pad(entity, iter) { iter->entity = entity; iter->index = i++; + + if (hweight32(iter->flags & (MEDIA_PAD_FL_SINK | + MEDIA_PAD_FL_SOURCE)) != 1) { + ret = -EINVAL; + break; + } + if (mdev) media_gobj_create(mdev, MEDIA_GRAPH_PAD, &iter->graph_obj); } + if (ret && mdev) { + media_entity_for_each_pad(entity, iter) + media_gobj_destroy(&iter->graph_obj); + } + if (mdev) mutex_unlock(&mdev->graph_mutex); - return 0; + return ret; } EXPORT_SYMBOL_GPL(media_entity_pads_init); -- GitLab From 2d21fef54800bd6641f85a6821427260439c9539 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 12 Sep 2023 11:36:51 +0300 Subject: [PATCH 0510/1451] media: Add MIPI CSI-2 generic long packet type definition Add a definition for MIPI CSI-2 generic long packet types. The generic long packet types are numbered from 1 to 4. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- include/media/mipi-csi2.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/media/mipi-csi2.h b/include/media/mipi-csi2.h index c3d8f12234b1f..40fc0264250d7 100644 --- a/include/media/mipi-csi2.h +++ b/include/media/mipi-csi2.h @@ -19,6 +19,7 @@ #define MIPI_CSI2_DT_NULL 0x10 #define MIPI_CSI2_DT_BLANKING 0x11 #define MIPI_CSI2_DT_EMBEDDED_8B 0x12 +#define MIPI_CSI2_DT_GENERIC_LONG(n) (0x13 + (n) - 1) /* 1..4 */ #define MIPI_CSI2_DT_YUV420_8B 0x18 #define MIPI_CSI2_DT_YUV420_10B 0x19 #define MIPI_CSI2_DT_YUV420_8B_LEGACY 0x1a -- GitLab From dc887661be33dd88e97bd0baaa899a9bd6d7eb8b Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 27 Sep 2023 14:22:52 +0300 Subject: [PATCH 0511/1451] media: Documentation: Split camera sensor documentation Split camera sensor documentation into user and kernel portions. This should make it easier for the user space developers to find the relevant documentation. Also add a list of exemplary drivers and add imx219 driver to it, besides those that were already mentioned. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Signed-off-by: Hans Verkuil --- .../driver-api/media/camera-sensor.rst | 131 +++++------------- .../media/drivers/camera-sensor.rst | 104 ++++++++++++++ .../userspace-api/media/drivers/index.rst | 1 + .../userspace-api/media/v4l/control.rst | 4 + 4 files changed, 147 insertions(+), 93 deletions(-) create mode 100644 Documentation/userspace-api/media/drivers/camera-sensor.rst diff --git a/Documentation/driver-api/media/camera-sensor.rst b/Documentation/driver-api/media/camera-sensor.rst index 2acc08142a1a5..6456145f96ed0 100644 --- a/Documentation/driver-api/media/camera-sensor.rst +++ b/Documentation/driver-api/media/camera-sensor.rst @@ -1,8 +1,14 @@ .. SPDX-License-Identifier: GPL-2.0 +.. _media_writing_camera_sensor_drivers: + Writing camera sensor drivers ============================= +This document covers the in-kernel APIs only. For the best practices on +userspace API implementation in camera sensor drivers, please see +:ref:`media_using_camera_sensor_drivers`. + CSI-2 and parallel (BT.601 and BT.656) busses --------------------------------------------- @@ -34,7 +40,8 @@ Devicetree The preferred way to achieve this is using ``assigned-clocks``, ``assigned-clock-parents`` and ``assigned-clock-rates`` properties. See the -`clock device tree bindings `_ +`clock device tree bindings +`_ for more information. The driver then gets the frequency using ``clk_get_rate()``. @@ -85,9 +92,7 @@ PM instead. If you feel you need to begin calling ``.s_power()`` from an ISP or a bridge driver, instead add runtime PM support to the sensor driver you are using and drop its ``.s_power()`` handler. -See examples of runtime PM handling in e.g. ``drivers/media/i2c/ov8856.c`` and -``drivers/media/i2c/ccs/ccs-core.c``. The two drivers work in both ACPI and DT -based systems. +Please also see :ref:`examples `. Control framework ~~~~~~~~~~~~~~~~~ @@ -104,99 +109,39 @@ The function returns a non-zero value if it succeeded getting the power count or runtime PM was disabled, in either of which cases the driver may proceed to access the device. -Frame size ----------- - -There are two distinct ways to configure the frame size produced by camera -sensors. - -Freely configurable camera sensor drivers -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Freely configurable camera sensor drivers expose the device's internal -processing pipeline as one or more sub-devices with different cropping and -scaling configurations. The output size of the device is the result of a series -of cropping and scaling operations from the device's pixel array's size. - -An example of such a driver is the CCS driver (see ``drivers/media/i2c/ccs``). - -Register list based drivers -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Register list based drivers generally, instead of able to configure the device -they control based on user requests, are limited to a number of preset -configurations that combine a number of different parameters that on hardware -level are independent. How a driver picks such configuration is based on the -format set on a source pad at the end of the device's internal pipeline. - -Most sensor drivers are implemented this way, see e.g. -``drivers/media/i2c/imx319.c`` for an example. - -Frame interval configuration ----------------------------- - -There are two different methods for obtaining possibilities for different frame -intervals as well as configuring the frame interval. Which one to implement -depends on the type of the device. - -Raw camera sensors -~~~~~~~~~~~~~~~~~~ - -Instead of a high level parameter such as frame interval, the frame interval is -a result of the configuration of a number of camera sensor implementation -specific parameters. Luckily, these parameters tend to be the same for more or -less all modern raw camera sensors. - -The frame interval is calculated using the following equation:: - - frame interval = (analogue crop width + horizontal blanking) * - (analogue crop height + vertical blanking) / pixel rate - -The formula is bus independent and is applicable for raw timing parameters on -large variety of devices beyond camera sensors. Devices that have no analogue -crop, use the full source image size, i.e. pixel array size. - -Horizontal and vertical blanking are specified by ``V4L2_CID_HBLANK`` and -``V4L2_CID_VBLANK``, respectively. The unit of the ``V4L2_CID_HBLANK`` control -is pixels and the unit of the ``V4L2_CID_VBLANK`` is lines. The pixel rate in -the sensor's **pixel array** is specified by ``V4L2_CID_PIXEL_RATE`` in the same -sub-device. The unit of that control is pixels per second. - -Register list based drivers need to implement read-only sub-device nodes for the -purpose. Devices that are not register list based need these to configure the -device's internal processing pipeline. - -The first entity in the linear pipeline is the pixel array. The pixel array may -be followed by other entities that are there to allow configuring binning, -skipping, scaling or digital crop :ref:`v4l2-subdev-selections`. - -USB cameras etc. devices -~~~~~~~~~~~~~~~~~~~~~~~~ - -USB video class hardware, as well as many cameras offering a similar higher -level interface natively, generally use the concept of frame interval (or frame -rate) on device level in firmware or hardware. This means lower level controls -implemented by raw cameras may not be used on uAPI (or even kAPI) to control the -frame interval on these devices. - Rotation, orientation and flipping ---------------------------------- -Some systems have the camera sensor mounted upside down compared to its natural -mounting rotation. In such cases, drivers shall expose the information to -userspace with the :ref:`V4L2_CID_CAMERA_SENSOR_ROTATION -` control. - -Sensor drivers shall also report the sensor's mounting orientation with the -:ref:`V4L2_CID_CAMERA_SENSOR_ORIENTATION `. - Use ``v4l2_fwnode_device_parse()`` to obtain rotation and orientation information from system firmware and ``v4l2_ctrl_new_fwnode_properties()`` to register the appropriate controls. -Sensor drivers that have any vertical or horizontal flips embedded in the -register programming sequences shall initialize the V4L2_CID_HFLIP and -V4L2_CID_VFLIP controls with the values programmed by the register sequences. -The default values of these controls shall be 0 (disabled). Especially these -controls shall not be inverted, independently of the sensor's mounting -rotation. +.. _media-camera-sensor-examples: + +Example drivers +--------------- + +Features implemented by sensor drivers vary, and depending on the set of +supported features and other qualities, particular sensor drivers better serve +the purpose of an example. The following drivers are known to be good examples: + +.. flat-table:: Example sensor drivers + :header-rows: 0 + :widths: 1 1 1 2 + + * - Driver name + - File(s) + - Driver type + - Example topic + * - CCS + - ``drivers/media/i2c/ccs/`` + - Freely configurable + - Power management (ACPI and DT), UAPI + * - imx219 + - ``drivers/media/i2c/imx219.c`` + - Register list based + - Power management (DT), UAPI, mode selection + * - imx319 + - ``drivers/media/i2c/imx319.c`` + - Register list based + - Power management (ACPI and DT) diff --git a/Documentation/userspace-api/media/drivers/camera-sensor.rst b/Documentation/userspace-api/media/drivers/camera-sensor.rst new file mode 100644 index 0000000000000..919a50e8b9d9c --- /dev/null +++ b/Documentation/userspace-api/media/drivers/camera-sensor.rst @@ -0,0 +1,104 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. _media_using_camera_sensor_drivers: + +Using camera sensor drivers +=========================== + +This section describes common practices for how the V4L2 sub-device interface is +used to control the camera sensor drivers. + +You may also find :ref:`media_writing_camera_sensor_drivers` useful. + +Frame size +---------- + +There are two distinct ways to configure the frame size produced by camera +sensors. + +Freely configurable camera sensor drivers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Freely configurable camera sensor drivers expose the device's internal +processing pipeline as one or more sub-devices with different cropping and +scaling configurations. The output size of the device is the result of a series +of cropping and scaling operations from the device's pixel array's size. + +An example of such a driver is the CCS driver. + +Register list based drivers +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Register list based drivers generally, instead of able to configure the device +they control based on user requests, are limited to a number of preset +configurations that combine a number of different parameters that on hardware +level are independent. How a driver picks such configuration is based on the +format set on a source pad at the end of the device's internal pipeline. + +Most sensor drivers are implemented this way. + +Frame interval configuration +---------------------------- + +There are two different methods for obtaining possibilities for different frame +intervals as well as configuring the frame interval. Which one to implement +depends on the type of the device. + +Raw camera sensors +~~~~~~~~~~~~~~~~~~ + +Instead of a high level parameter such as frame interval, the frame interval is +a result of the configuration of a number of camera sensor implementation +specific parameters. Luckily, these parameters tend to be the same for more or +less all modern raw camera sensors. + +The frame interval is calculated using the following equation:: + + frame interval = (analogue crop width + horizontal blanking) * + (analogue crop height + vertical blanking) / pixel rate + +The formula is bus independent and is applicable for raw timing parameters on +large variety of devices beyond camera sensors. Devices that have no analogue +crop, use the full source image size, i.e. pixel array size. + +Horizontal and vertical blanking are specified by ``V4L2_CID_HBLANK`` and +``V4L2_CID_VBLANK``, respectively. The unit of the ``V4L2_CID_HBLANK`` control +is pixels and the unit of the ``V4L2_CID_VBLANK`` is lines. The pixel rate in +the sensor's **pixel array** is specified by ``V4L2_CID_PIXEL_RATE`` in the same +sub-device. The unit of that control is pixels per second. + +Register list based drivers need to implement read-only sub-device nodes for the +purpose. Devices that are not register list based need these to configure the +device's internal processing pipeline. + +The first entity in the linear pipeline is the pixel array. The pixel array may +be followed by other entities that are there to allow configuring binning, +skipping, scaling or digital crop, see :ref:`VIDIOC_SUBDEV_G_SELECTION +`. + +USB cameras etc. devices +~~~~~~~~~~~~~~~~~~~~~~~~ + +USB video class hardware, as well as many cameras offering a similar higher +level interface natively, generally use the concept of frame interval (or frame +rate) on device level in firmware or hardware. This means lower level controls +implemented by raw cameras may not be used on uAPI (or even kAPI) to control the +frame interval on these devices. + +Rotation, orientation and flipping +---------------------------------- + +Some systems have the camera sensor mounted upside down compared to its natural +mounting rotation. In such cases, drivers shall expose the information to +userspace with the :ref:`V4L2_CID_CAMERA_SENSOR_ROTATION +` control. + +Sensor drivers shall also report the sensor's mounting orientation with the +:ref:`V4L2_CID_CAMERA_SENSOR_ORIENTATION `. + +Sensor drivers that have any vertical or horizontal flips embedded in the +register programming sequences shall initialize the :ref:`V4L2_CID_HFLIP +` and :ref:`V4L2_CID_VFLIP ` controls with the +values programmed by the register sequences. The default values of these +controls shall be 0 (disabled). Especially these controls shall not be inverted, +independently of the sensor's mounting rotation. diff --git a/Documentation/userspace-api/media/drivers/index.rst b/Documentation/userspace-api/media/drivers/index.rst index 783f92f01a4c8..1726f8ec86fa4 100644 --- a/Documentation/userspace-api/media/drivers/index.rst +++ b/Documentation/userspace-api/media/drivers/index.rst @@ -32,6 +32,7 @@ For more details see the file COPYING in the source distribution of Linux. :numbered: aspeed-video + camera-sensor ccs cx2341x-uapi dw100 diff --git a/Documentation/userspace-api/media/v4l/control.rst b/Documentation/userspace-api/media/v4l/control.rst index 4463fce694b08..57893814a1e5d 100644 --- a/Documentation/userspace-api/media/v4l/control.rst +++ b/Documentation/userspace-api/media/v4l/control.rst @@ -143,9 +143,13 @@ Control IDs recognise the difference between digital and analogue gain use controls ``V4L2_CID_DIGITAL_GAIN`` and ``V4L2_CID_ANALOGUE_GAIN``. +.. _v4l2-cid-hflip: + ``V4L2_CID_HFLIP`` ``(boolean)`` Mirror the picture horizontally. +.. _v4l2-cid-vflip: + ``V4L2_CID_VFLIP`` ``(boolean)`` Mirror the picture vertically. -- GitLab From 462e108bac18419f17c6a34eb348b600a614aa4f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 26 Sep 2023 11:58:42 +0200 Subject: [PATCH 0512/1451] media: rc: keymaps: add missing MODULE_DESCRIPTION to keymaps When building the modules 'modpost' warns about missing MODULE_DESCRIPTION. Since almost none of the rc keymap modules have this, it produces a lot of warnings. As a first step to fixing all media modules, add this line to all keymaps. The description should be a human-readable string describing the remote or the remote controller that the keymap can be used with. Note that keymaps/rc-cec.c is actually compiled into the rc-core, so that is the sole keymap source that didn't need this. Signed-off-by: Hans Verkuil Signed-off-by: Sean Young --- drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c | 1 + drivers/media/rc/keymaps/rc-alink-dtu-m.c | 1 + drivers/media/rc/keymaps/rc-anysee.c | 1 + drivers/media/rc/keymaps/rc-apac-viewcomp.c | 1 + drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c | 1 + drivers/media/rc/keymaps/rc-asus-pc39.c | 1 + drivers/media/rc/keymaps/rc-asus-ps3-100.c | 1 + drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c | 1 + drivers/media/rc/keymaps/rc-ati-x10.c | 1 + drivers/media/rc/keymaps/rc-avermedia-a16d.c | 1 + drivers/media/rc/keymaps/rc-avermedia-cardbus.c | 1 + drivers/media/rc/keymaps/rc-avermedia-dvbt.c | 1 + drivers/media/rc/keymaps/rc-avermedia-m135a.c | 1 + drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c | 1 + drivers/media/rc/keymaps/rc-avermedia-rm-ks.c | 1 + drivers/media/rc/keymaps/rc-avermedia.c | 1 + drivers/media/rc/keymaps/rc-avertv-303.c | 1 + drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c | 1 + drivers/media/rc/keymaps/rc-beelink-gs1.c | 1 + drivers/media/rc/keymaps/rc-beelink-mxiii.c | 1 + drivers/media/rc/keymaps/rc-behold-columbus.c | 1 + drivers/media/rc/keymaps/rc-behold.c | 1 + drivers/media/rc/keymaps/rc-budget-ci-old.c | 1 + drivers/media/rc/keymaps/rc-cinergy-1400.c | 1 + drivers/media/rc/keymaps/rc-cinergy.c | 1 + drivers/media/rc/keymaps/rc-ct-90405.c | 1 + drivers/media/rc/keymaps/rc-d680-dmb.c | 1 + drivers/media/rc/keymaps/rc-dib0700-nec.c | 1 + drivers/media/rc/keymaps/rc-dib0700-rc5.c | 1 + drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c | 1 + drivers/media/rc/keymaps/rc-digittrade.c | 1 + drivers/media/rc/keymaps/rc-dm1105-nec.c | 1 + drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c | 1 + drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c | 1 + drivers/media/rc/keymaps/rc-dreambox.c | 1 + drivers/media/rc/keymaps/rc-dtt200u.c | 1 + drivers/media/rc/keymaps/rc-dvbsky.c | 1 + drivers/media/rc/keymaps/rc-dvico-mce.c | 1 + drivers/media/rc/keymaps/rc-dvico-portable.c | 1 + drivers/media/rc/keymaps/rc-em-terratec.c | 1 + drivers/media/rc/keymaps/rc-encore-enltv-fm53.c | 1 + drivers/media/rc/keymaps/rc-encore-enltv.c | 1 + drivers/media/rc/keymaps/rc-encore-enltv2.c | 1 + drivers/media/rc/keymaps/rc-evga-indtube.c | 1 + drivers/media/rc/keymaps/rc-eztv.c | 1 + drivers/media/rc/keymaps/rc-flydvb.c | 1 + drivers/media/rc/keymaps/rc-flyvideo.c | 1 + drivers/media/rc/keymaps/rc-fusionhdtv-mce.c | 1 + drivers/media/rc/keymaps/rc-gadmei-rm008z.c | 1 + drivers/media/rc/keymaps/rc-geekbox.c | 1 + drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c | 1 + drivers/media/rc/keymaps/rc-gotview7135.c | 1 + drivers/media/rc/keymaps/rc-hauppauge.c | 1 + drivers/media/rc/keymaps/rc-hisi-poplar.c | 1 + drivers/media/rc/keymaps/rc-hisi-tv-demo.c | 1 + drivers/media/rc/keymaps/rc-imon-mce.c | 1 + drivers/media/rc/keymaps/rc-imon-pad.c | 1 + drivers/media/rc/keymaps/rc-imon-rsc.c | 1 + drivers/media/rc/keymaps/rc-iodata-bctv7e.c | 1 + drivers/media/rc/keymaps/rc-it913x-v1.c | 1 + drivers/media/rc/keymaps/rc-it913x-v2.c | 1 + drivers/media/rc/keymaps/rc-kaiomy.c | 1 + drivers/media/rc/keymaps/rc-khadas.c | 1 + drivers/media/rc/keymaps/rc-khamsin.c | 1 + drivers/media/rc/keymaps/rc-kworld-315u.c | 1 + drivers/media/rc/keymaps/rc-kworld-pc150u.c | 1 + drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c | 1 + drivers/media/rc/keymaps/rc-leadtek-y04g0051.c | 1 + drivers/media/rc/keymaps/rc-lme2510.c | 1 + drivers/media/rc/keymaps/rc-manli.c | 1 + drivers/media/rc/keymaps/rc-mecool-kii-pro.c | 1 + drivers/media/rc/keymaps/rc-mecool-kiii-pro.c | 1 + drivers/media/rc/keymaps/rc-medion-x10.c | 1 + drivers/media/rc/keymaps/rc-minix-neo.c | 1 + drivers/media/rc/keymaps/rc-msi-digivox-ii.c | 1 + drivers/media/rc/keymaps/rc-msi-digivox-iii.c | 1 + drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c | 1 + drivers/media/rc/keymaps/rc-msi-tvanywhere.c | 1 + drivers/media/rc/keymaps/rc-nebula.c | 1 + drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c | 1 + drivers/media/rc/keymaps/rc-norwood.c | 1 + drivers/media/rc/keymaps/rc-npgtech.c | 1 + drivers/media/rc/keymaps/rc-odroid.c | 1 + drivers/media/rc/keymaps/rc-pctv-sedna.c | 1 + drivers/media/rc/keymaps/rc-pine64.c | 1 + drivers/media/rc/keymaps/rc-pinnacle-color.c | 1 + drivers/media/rc/keymaps/rc-pinnacle-grey.c | 1 + drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c | 1 + drivers/media/rc/keymaps/rc-pixelview-002t.c | 1 + drivers/media/rc/keymaps/rc-pixelview-mk12.c | 1 + drivers/media/rc/keymaps/rc-pixelview-new.c | 1 + drivers/media/rc/keymaps/rc-pixelview.c | 1 + drivers/media/rc/keymaps/rc-powercolor-real-angel.c | 1 + drivers/media/rc/keymaps/rc-proteus-2309.c | 1 + drivers/media/rc/keymaps/rc-purpletv.c | 1 + drivers/media/rc/keymaps/rc-pv951.c | 1 + drivers/media/rc/keymaps/rc-rc6-mce.c | 1 + drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c | 1 + drivers/media/rc/keymaps/rc-reddo.c | 1 + drivers/media/rc/keymaps/rc-snapstream-firefly.c | 1 + drivers/media/rc/keymaps/rc-streamzap.c | 1 + drivers/media/rc/keymaps/rc-su3000.c | 1 + drivers/media/rc/keymaps/rc-tanix-tx3mini.c | 1 + drivers/media/rc/keymaps/rc-tanix-tx5max.c | 1 + drivers/media/rc/keymaps/rc-tbs-nec.c | 1 + drivers/media/rc/keymaps/rc-technisat-ts35.c | 1 + drivers/media/rc/keymaps/rc-technisat-usb2.c | 1 + drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c | 1 + drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c | 1 + drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c | 1 + drivers/media/rc/keymaps/rc-terratec-slim-2.c | 1 + drivers/media/rc/keymaps/rc-terratec-slim.c | 1 + drivers/media/rc/keymaps/rc-tevii-nec.c | 1 + drivers/media/rc/keymaps/rc-tivo.c | 1 + drivers/media/rc/keymaps/rc-total-media-in-hand-02.c | 1 + drivers/media/rc/keymaps/rc-total-media-in-hand.c | 1 + drivers/media/rc/keymaps/rc-trekstor.c | 1 + drivers/media/rc/keymaps/rc-tt-1500.c | 1 + drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c | 1 + drivers/media/rc/keymaps/rc-twinhan1027.c | 1 + drivers/media/rc/keymaps/rc-vega-s9x.c | 1 + drivers/media/rc/keymaps/rc-videomate-m1f.c | 1 + drivers/media/rc/keymaps/rc-videomate-s350.c | 1 + drivers/media/rc/keymaps/rc-videomate-tv-pvr.c | 1 + drivers/media/rc/keymaps/rc-videostrong-kii-pro.c | 1 + drivers/media/rc/keymaps/rc-wetek-hub.c | 1 + drivers/media/rc/keymaps/rc-wetek-play2.c | 1 + drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c | 1 + drivers/media/rc/keymaps/rc-winfast.c | 1 + drivers/media/rc/keymaps/rc-x96max.c | 1 + drivers/media/rc/keymaps/rc-xbox-360.c | 1 + drivers/media/rc/keymaps/rc-xbox-dvd.c | 1 + drivers/media/rc/keymaps/rc-zx-irdec.c | 1 + 133 files changed, 133 insertions(+) diff --git a/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c index 0a867ca90038f..e24946c8fe204 100644 --- a/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c +++ b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c @@ -83,3 +83,4 @@ module_exit(exit_rc_map_adstech_dvb_t_pci) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("ADS Tech Instant TV DVB-T PCI Remote"); diff --git a/drivers/media/rc/keymaps/rc-alink-dtu-m.c b/drivers/media/rc/keymaps/rc-alink-dtu-m.c index 8a2ccaf3b8174..9926259b43ee0 100644 --- a/drivers/media/rc/keymaps/rc-alink-dtu-m.c +++ b/drivers/media/rc/keymaps/rc-alink-dtu-m.c @@ -54,3 +54,4 @@ module_exit(exit_rc_map_alink_dtu_m) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("A-Link DTU(m) slim remote, 6 rows, 3 columns."); diff --git a/drivers/media/rc/keymaps/rc-anysee.c b/drivers/media/rc/keymaps/rc-anysee.c index 34da03c46104b..e4bcbf889fed4 100644 --- a/drivers/media/rc/keymaps/rc-anysee.c +++ b/drivers/media/rc/keymaps/rc-anysee.c @@ -79,3 +79,4 @@ module_exit(exit_rc_map_anysee) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Anysee remote keytable"); diff --git a/drivers/media/rc/keymaps/rc-apac-viewcomp.c b/drivers/media/rc/keymaps/rc-apac-viewcomp.c index bdc47e25d46e8..80b096f02e995 100644 --- a/drivers/media/rc/keymaps/rc-apac-viewcomp.c +++ b/drivers/media/rc/keymaps/rc-apac-viewcomp.c @@ -74,3 +74,4 @@ module_exit(exit_rc_map_apac_viewcomp) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("apac-viewcomp remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c b/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c index 1d322137898e3..212b0d9209013 100644 --- a/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c +++ b/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c @@ -62,3 +62,4 @@ module_exit(exit_rc_map_t2hybrid) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Oleh Kravchenko "); +MODULE_DESCRIPTION("Astrometa T2hybrid remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-asus-pc39.c b/drivers/media/rc/keymaps/rc-asus-pc39.c index 7a4b3a6e3a49e..bd55b7c6f82a4 100644 --- a/drivers/media/rc/keymaps/rc-asus-pc39.c +++ b/drivers/media/rc/keymaps/rc-asus-pc39.c @@ -85,3 +85,4 @@ module_exit(exit_rc_map_asus_pc39) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Model PC-39 keytable for asus-pc39 remote controller"); diff --git a/drivers/media/rc/keymaps/rc-asus-ps3-100.c b/drivers/media/rc/keymaps/rc-asus-ps3-100.c index 09b60fa335e3d..9d63c1e4a17a2 100644 --- a/drivers/media/rc/keymaps/rc-asus-ps3-100.c +++ b/drivers/media/rc/keymaps/rc-asus-ps3-100.c @@ -84,3 +84,4 @@ module_exit(exit_rc_map_asus_ps3_100) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Asus My Cinema PS3-100 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c b/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c index b4b7932c0c5a1..063237f0d2e20 100644 --- a/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c +++ b/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c @@ -63,3 +63,4 @@ module_exit(exit_rc_map_ati_tv_wonder_hd_600) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("ati-tv-wonder-hd-600 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-ati-x10.c b/drivers/media/rc/keymaps/rc-ati-x10.c index 31fe1106b7087..9f7cbe9a1ac84 100644 --- a/drivers/media/rc/keymaps/rc-ati-x10.c +++ b/drivers/media/rc/keymaps/rc-ati-x10.c @@ -123,3 +123,4 @@ module_exit(exit_rc_map_ati_x10) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Anssi Hannula "); +MODULE_DESCRIPTION("ATI X10 RF remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-avermedia-a16d.c b/drivers/media/rc/keymaps/rc-avermedia-a16d.c index 6467ff6e48d77..98497f4f6f928 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-a16d.c +++ b/drivers/media/rc/keymaps/rc-avermedia-a16d.c @@ -69,3 +69,4 @@ module_exit(exit_rc_map_avermedia_a16d) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("avermedia-a16d remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c index 54fc6d9022c2f..5832c2f8ab3fa 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c +++ b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c @@ -91,3 +91,4 @@ module_exit(exit_rc_map_avermedia_cardbus) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("avermedia-cardbus remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c index 92c6df3360b33..3157d0c1cee97 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c +++ b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c @@ -72,3 +72,4 @@ module_exit(exit_rc_map_avermedia_dvbt) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("avermedia-dvbt remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-avermedia-m135a.c b/drivers/media/rc/keymaps/rc-avermedia-m135a.c index 311ddeb061cac..cc1318ad09d9e 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-m135a.c +++ b/drivers/media/rc/keymaps/rc-avermedia-m135a.c @@ -142,3 +142,4 @@ module_exit(exit_rc_map_avermedia_m135a) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Avermedia M135A with RM-JX and RM-K6 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c index a970ed5a090be..ec6c866c9f5d9 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c +++ b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c @@ -90,3 +90,4 @@ module_exit(exit_rc_map_avermedia_m733a_rm_k6) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Avermedia M733A with IR model RM-K6 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c index cf8a4fd107f43..ee4fe5791add5 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c +++ b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c @@ -65,3 +65,4 @@ module_exit(exit_rc_map_avermedia_rm_ks) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("AverMedia RM-KS remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-avermedia.c b/drivers/media/rc/keymaps/rc-avermedia.c index f96f229b70bb1..b827536a1f5f2 100644 --- a/drivers/media/rc/keymaps/rc-avermedia.c +++ b/drivers/media/rc/keymaps/rc-avermedia.c @@ -80,3 +80,4 @@ module_exit(exit_rc_map_avermedia) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("avermedia remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-avertv-303.c b/drivers/media/rc/keymaps/rc-avertv-303.c index a3e2e945c769e..71d1da42528d3 100644 --- a/drivers/media/rc/keymaps/rc-avertv-303.c +++ b/drivers/media/rc/keymaps/rc-avertv-303.c @@ -79,3 +79,4 @@ module_exit(exit_rc_map_avertv_303) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("AVERTV STUDIO 303 Remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c b/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c index 5fc8e4cd102e7..56f8eb1f0d012 100644 --- a/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c +++ b/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c @@ -88,3 +88,4 @@ module_exit(exit_rc_map_azurewave_ad_tu700) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("TwinHan AzureWave AD-TU700(704J) remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-beelink-gs1.c b/drivers/media/rc/keymaps/rc-beelink-gs1.c index cedbd5d20bc76..6e767d88c707f 100644 --- a/drivers/media/rc/keymaps/rc-beelink-gs1.c +++ b/drivers/media/rc/keymaps/rc-beelink-gs1.c @@ -82,3 +82,4 @@ module_exit(exit_rc_map_beelink_gs1) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Clément Péron "); +MODULE_DESCRIPTION("Beelink GS1 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-beelink-mxiii.c b/drivers/media/rc/keymaps/rc-beelink-mxiii.c index 01180cd922053..88fad9959a866 100644 --- a/drivers/media/rc/keymaps/rc-beelink-mxiii.c +++ b/drivers/media/rc/keymaps/rc-beelink-mxiii.c @@ -55,3 +55,4 @@ module_exit(exit_rc_map_beelink_mxiii) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt "); +MODULE_DESCRIPTION("Toshiba CT-90405 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-d680-dmb.c b/drivers/media/rc/keymaps/rc-d680-dmb.c index d491a5e9750f4..7870d36f2c697 100644 --- a/drivers/media/rc/keymaps/rc-d680-dmb.c +++ b/drivers/media/rc/keymaps/rc-d680-dmb.c @@ -70,3 +70,4 @@ module_exit(exit_rc_map_d680_dmb) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("d680-dmb remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-dib0700-nec.c b/drivers/media/rc/keymaps/rc-dib0700-nec.c index f1fcdf16f4852..0323049fd2b18 100644 --- a/drivers/media/rc/keymaps/rc-dib0700-nec.c +++ b/drivers/media/rc/keymaps/rc-dib0700-nec.c @@ -118,3 +118,4 @@ module_exit(exit_rc_map) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("dib0700-nec remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-dib0700-rc5.c b/drivers/media/rc/keymaps/rc-dib0700-rc5.c index 002fffcba95d3..d34e92eb92be7 100644 --- a/drivers/media/rc/keymaps/rc-dib0700-rc5.c +++ b/drivers/media/rc/keymaps/rc-dib0700-rc5.c @@ -229,3 +229,4 @@ module_exit(exit_rc_map) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("dib0700-rc5 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c b/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c index 2466d8c50226b..d18b8f93a018e 100644 --- a/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c +++ b/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c @@ -84,3 +84,4 @@ module_exit(exit_rc_map_digitalnow_tinytwin) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("DigitalNow TinyTwin remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-digittrade.c b/drivers/media/rc/keymaps/rc-digittrade.c index 65bc8ad7e52ce..129a81f59b4a1 100644 --- a/drivers/media/rc/keymaps/rc-digittrade.c +++ b/drivers/media/rc/keymaps/rc-digittrade.c @@ -68,3 +68,4 @@ module_exit(exit_rc_map_digittrade) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Digittrade DVB-T USB Stick remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-dm1105-nec.c b/drivers/media/rc/keymaps/rc-dm1105-nec.c index cd0b985c994df..b82290ce925ba 100644 --- a/drivers/media/rc/keymaps/rc-dm1105-nec.c +++ b/drivers/media/rc/keymaps/rc-dm1105-nec.c @@ -70,3 +70,4 @@ module_exit(exit_rc_map_dm1105_nec) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("dm1105-nec remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c index a82f64dc94117..4b23335615cf2 100644 --- a/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c +++ b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c @@ -72,3 +72,4 @@ module_exit(exit_rc_map_dntv_live_dvb_t) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("dntv-live-dvb-t remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c index d3f5048a0220f..46d8ea1b49a39 100644 --- a/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c +++ b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c @@ -91,3 +91,4 @@ module_exit(exit_rc_map_dntv_live_dvbt_pro) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("DigitalNow DNTV Live DVB-T Remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-dreambox.c b/drivers/media/rc/keymaps/rc-dreambox.c index dea024fa3a22a..e1ec99ce31050 100644 --- a/drivers/media/rc/keymaps/rc-dreambox.c +++ b/drivers/media/rc/keymaps/rc-dreambox.c @@ -149,3 +149,4 @@ module_exit(exit_rc_map_dreambox) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Emanuel Strobel "); +MODULE_DESCRIPTION("Dreambox RC10/RC0 and RC20/RC-BT remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-dtt200u.c b/drivers/media/rc/keymaps/rc-dtt200u.c index e7f87baa32124..eeb2f6e303d7a 100644 --- a/drivers/media/rc/keymaps/rc-dtt200u.c +++ b/drivers/media/rc/keymaps/rc-dtt200u.c @@ -53,3 +53,4 @@ module_exit(exit_rc_map_dtt200u) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jonathan McDowell "); +MODULE_DESCRIPTION("Wideview WT-220U remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-dvbsky.c b/drivers/media/rc/keymaps/rc-dvbsky.c index f5063af2e5bcc..1fcd47bd8595b 100644 --- a/drivers/media/rc/keymaps/rc-dvbsky.c +++ b/drivers/media/rc/keymaps/rc-dvbsky.c @@ -71,3 +71,4 @@ module_exit(exit_rc_map_rc5_dvbsky) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Nibble Max "); +MODULE_DESCRIPTION("DVBSky remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-dvico-mce.c b/drivers/media/rc/keymaps/rc-dvico-mce.c index b1bb8cdb3705d..4bb4222d259e4 100644 --- a/drivers/media/rc/keymaps/rc-dvico-mce.c +++ b/drivers/media/rc/keymaps/rc-dvico-mce.c @@ -80,3 +80,4 @@ module_exit(exit_rc_map_dvico_mce) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("dvico-mce remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-dvico-portable.c b/drivers/media/rc/keymaps/rc-dvico-portable.c index ec12ba6995dc1..ba9ef9b757775 100644 --- a/drivers/media/rc/keymaps/rc-dvico-portable.c +++ b/drivers/media/rc/keymaps/rc-dvico-portable.c @@ -71,3 +71,4 @@ module_exit(exit_rc_map_dvico_portable) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("dvico-portable remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-em-terratec.c b/drivers/media/rc/keymaps/rc-em-terratec.c index a1f59aa6ff233..8a51fe6328405 100644 --- a/drivers/media/rc/keymaps/rc-em-terratec.c +++ b/drivers/media/rc/keymaps/rc-em-terratec.c @@ -63,3 +63,4 @@ module_exit(exit_rc_map_em_terratec) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("em-terratec remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c index 7a00471b60052..320e184f42983 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c @@ -75,3 +75,4 @@ module_exit(exit_rc_map_encore_enltv_fm53) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Encore ENLTV-FM v5.3 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-encore-enltv.c b/drivers/media/rc/keymaps/rc-encore-enltv.c index 712210097b4db..0b235d72e57d2 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv.c @@ -106,3 +106,4 @@ module_exit(exit_rc_map_encore_enltv) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Encore ENLTV-FM remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-encore-enltv2.c b/drivers/media/rc/keymaps/rc-encore-enltv2.c index a08470b4f1871..d8057f41252d0 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv2.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv2.c @@ -84,3 +84,4 @@ module_exit(exit_rc_map_encore_enltv2) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Encore ENLTV2-FM remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-evga-indtube.c b/drivers/media/rc/keymaps/rc-evga-indtube.c index f4398444330b9..95295f6882b10 100644 --- a/drivers/media/rc/keymaps/rc-evga-indtube.c +++ b/drivers/media/rc/keymaps/rc-evga-indtube.c @@ -55,3 +55,4 @@ module_exit(exit_rc_map_evga_indtube) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("EVGA inDtube remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-eztv.c b/drivers/media/rc/keymaps/rc-eztv.c index 4e494d953e33b..522e772f7c2ba 100644 --- a/drivers/media/rc/keymaps/rc-eztv.c +++ b/drivers/media/rc/keymaps/rc-eztv.c @@ -90,3 +90,4 @@ module_exit(exit_rc_map_eztv) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("eztv remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-flydvb.c b/drivers/media/rc/keymaps/rc-flydvb.c index 202a1fbd19356..fcb3bcadd82d9 100644 --- a/drivers/media/rc/keymaps/rc-flydvb.c +++ b/drivers/media/rc/keymaps/rc-flydvb.c @@ -71,3 +71,4 @@ module_exit(exit_rc_map_flydvb) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("flydvb remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-flyvideo.c b/drivers/media/rc/keymaps/rc-flyvideo.c index a44467fb15cb9..fcb70c9507cf4 100644 --- a/drivers/media/rc/keymaps/rc-flyvideo.c +++ b/drivers/media/rc/keymaps/rc-flyvideo.c @@ -64,3 +64,4 @@ module_exit(exit_rc_map_flyvideo) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("flyvideo remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c index 253199f5531af..43f73db910988 100644 --- a/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c +++ b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c @@ -92,3 +92,4 @@ module_exit(exit_rc_map_fusionhdtv_mce) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("DViCO FUSION HDTV MCE remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-gadmei-rm008z.c b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c index c630ef306f116..8a446d1257892 100644 --- a/drivers/media/rc/keymaps/rc-gadmei-rm008z.c +++ b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c @@ -75,3 +75,4 @@ module_exit(exit_rc_map_gadmei_rm008z) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("GADMEI UTV330+ RM008Z remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-geekbox.c b/drivers/media/rc/keymaps/rc-geekbox.c index 11735ad36c6aa..d3f2e960c9253 100644 --- a/drivers/media/rc/keymaps/rc-geekbox.c +++ b/drivers/media/rc/keymaps/rc-geekbox.c @@ -47,3 +47,4 @@ module_exit(exit_rc_map_geekbox) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Martin Blumenstingl "); +MODULE_DESCRIPTION("GeekBox remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c index c966c130b05d0..e49828ea2b80e 100644 --- a/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c +++ b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c @@ -78,3 +78,4 @@ module_exit(exit_rc_map_genius_tvgo_a11mce) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Genius TVGO A11MCE remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-gotview7135.c b/drivers/media/rc/keymaps/rc-gotview7135.c index 0dc4ef36d76f8..a044991e30bad 100644 --- a/drivers/media/rc/keymaps/rc-gotview7135.c +++ b/drivers/media/rc/keymaps/rc-gotview7135.c @@ -73,3 +73,4 @@ module_exit(exit_rc_map_gotview7135) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("gotview7135 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-hauppauge.c b/drivers/media/rc/keymaps/rc-hauppauge.c index 82552360c3c38..d7156774aa0e1 100644 --- a/drivers/media/rc/keymaps/rc-hauppauge.c +++ b/drivers/media/rc/keymaps/rc-hauppauge.c @@ -287,3 +287,4 @@ module_exit(exit_rc_map_rc5_hauppauge_new) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Hauppauge remote controllers keytable"); diff --git a/drivers/media/rc/keymaps/rc-hisi-poplar.c b/drivers/media/rc/keymaps/rc-hisi-poplar.c index 49a18e9169154..b10ad674c32a2 100644 --- a/drivers/media/rc/keymaps/rc-hisi-poplar.c +++ b/drivers/media/rc/keymaps/rc-hisi-poplar.c @@ -63,3 +63,4 @@ module_init(init_rc_map_hisi_poplar) module_exit(exit_rc_map_hisi_poplar) MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("HiSilicon poplar remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-hisi-tv-demo.c b/drivers/media/rc/keymaps/rc-hisi-tv-demo.c index c73068b653f7c..24dcb38df27c9 100644 --- a/drivers/media/rc/keymaps/rc-hisi-tv-demo.c +++ b/drivers/media/rc/keymaps/rc-hisi-tv-demo.c @@ -75,3 +75,4 @@ module_init(init_rc_map_hisi_tv_demo) module_exit(exit_rc_map_hisi_tv_demo) MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("HiSilicon tv demo remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-imon-mce.c b/drivers/media/rc/keymaps/rc-imon-mce.c index b89e3569e76ac..130f685ae30ea 100644 --- a/drivers/media/rc/keymaps/rc-imon-mce.c +++ b/drivers/media/rc/keymaps/rc-imon-mce.c @@ -137,3 +137,4 @@ module_exit(exit_rc_map_imon_mce) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jarod Wilson "); +MODULE_DESCRIPTION("iMON MCE remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-imon-pad.c b/drivers/media/rc/keymaps/rc-imon-pad.c index bceb4e7726b64..cd5ba44d033cb 100644 --- a/drivers/media/rc/keymaps/rc-imon-pad.c +++ b/drivers/media/rc/keymaps/rc-imon-pad.c @@ -150,3 +150,4 @@ module_exit(exit_rc_map_imon_pad) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jarod Wilson "); +MODULE_DESCRIPTION("iMON PAD remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-imon-rsc.c b/drivers/media/rc/keymaps/rc-imon-rsc.c index 38787dd0e4a0f..e4124fadf7051 100644 --- a/drivers/media/rc/keymaps/rc-imon-rsc.c +++ b/drivers/media/rc/keymaps/rc-imon-rsc.c @@ -80,3 +80,4 @@ module_exit(exit_rc_map_imon_rsc) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Sean Young "); +MODULE_DESCRIPTION("iMON RSC remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-iodata-bctv7e.c b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c index 9cc6ea0f42263..95256e85458a4 100644 --- a/drivers/media/rc/keymaps/rc-iodata-bctv7e.c +++ b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c @@ -82,3 +82,4 @@ module_exit(exit_rc_map_iodata_bctv7e) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("IO-DATA BCTV7E remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-it913x-v1.c b/drivers/media/rc/keymaps/rc-it913x-v1.c index 1e049f26a2465..d80764c98f44e 100644 --- a/drivers/media/rc/keymaps/rc-it913x-v1.c +++ b/drivers/media/rc/keymaps/rc-it913x-v1.c @@ -89,3 +89,4 @@ module_exit(exit_rc_it913x_v1_map) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); +MODULE_DESCRIPTION("it913x-v1 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-it913x-v2.c b/drivers/media/rc/keymaps/rc-it913x-v2.c index da3107da26b75..c37358cf8b86e 100644 --- a/drivers/media/rc/keymaps/rc-it913x-v2.c +++ b/drivers/media/rc/keymaps/rc-it913x-v2.c @@ -88,3 +88,4 @@ module_exit(exit_rc_it913x_v2_map) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); +MODULE_DESCRIPTION("it913x-v2 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-kaiomy.c b/drivers/media/rc/keymaps/rc-kaiomy.c index 548760e86a2d3..bea50c6f7e99c 100644 --- a/drivers/media/rc/keymaps/rc-kaiomy.c +++ b/drivers/media/rc/keymaps/rc-kaiomy.c @@ -81,3 +81,4 @@ module_exit(exit_rc_map_kaiomy) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Kaiomy TVnPC U2 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-khadas.c b/drivers/media/rc/keymaps/rc-khadas.c index ce4938444d90c..2b7161e1bc3f2 100644 --- a/drivers/media/rc/keymaps/rc-khadas.c +++ b/drivers/media/rc/keymaps/rc-khadas.c @@ -52,3 +52,4 @@ module_exit(exit_rc_map_khadas) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt "); +MODULE_DESCRIPTION("Khadas VIM/EDGE SBC remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-khamsin.c b/drivers/media/rc/keymaps/rc-khamsin.c index 0c98c2faacffc..2121cad8d3df8 100644 --- a/drivers/media/rc/keymaps/rc-khamsin.c +++ b/drivers/media/rc/keymaps/rc-khamsin.c @@ -73,3 +73,4 @@ module_exit(exit_rc_map_khamsin) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt "); +MODULE_DESCRIPTION("KHAMSIN remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-kworld-315u.c b/drivers/media/rc/keymaps/rc-kworld-315u.c index f5aed4b960191..f849dd6b7ef27 100644 --- a/drivers/media/rc/keymaps/rc-kworld-315u.c +++ b/drivers/media/rc/keymaps/rc-kworld-315u.c @@ -77,3 +77,4 @@ module_exit(exit_rc_map_kworld_315u) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Kworld 315U remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-kworld-pc150u.c b/drivers/media/rc/keymaps/rc-kworld-pc150u.c index 7938761eb9949..630ef7c330d96 100644 --- a/drivers/media/rc/keymaps/rc-kworld-pc150u.c +++ b/drivers/media/rc/keymaps/rc-kworld-pc150u.c @@ -96,3 +96,4 @@ module_exit(exit_rc_map_kworld_pc150u) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kyle Strickland "); +MODULE_DESCRIPTION("Kworld PC150-U remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c index 75389b74e02db..1fb9dc4346852 100644 --- a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c +++ b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c @@ -97,3 +97,4 @@ module_exit(exit_rc_map_kworld_plus_tv_analog) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Kworld Plus TV Analog Lite PCI IR remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c b/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c index 2f2b981e19955..c637312643b70 100644 --- a/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c +++ b/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c @@ -85,3 +85,4 @@ module_exit(exit_rc_map_leadtek_y04g0051) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("LeadTek Y04G0051 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-lme2510.c b/drivers/media/rc/keymaps/rc-lme2510.c index 181e48f0cb679..575485655a85f 100644 --- a/drivers/media/rc/keymaps/rc-lme2510.c +++ b/drivers/media/rc/keymaps/rc-lme2510.c @@ -104,3 +104,4 @@ module_exit(exit_rc_lme2510_map) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); +MODULE_DESCRIPTION("LME2510 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-manli.c b/drivers/media/rc/keymaps/rc-manli.c index e884aeb5c3d60..b81149a0dfd8d 100644 --- a/drivers/media/rc/keymaps/rc-manli.c +++ b/drivers/media/rc/keymaps/rc-manli.c @@ -128,3 +128,4 @@ module_exit(exit_rc_map_manli) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("MANLI MTV00[0x0c] and BeholdTV 40[13] remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-mecool-kii-pro.c b/drivers/media/rc/keymaps/rc-mecool-kii-pro.c index 77ca8a8fade80..273fe1a304f01 100644 --- a/drivers/media/rc/keymaps/rc-mecool-kii-pro.c +++ b/drivers/media/rc/keymaps/rc-mecool-kii-pro.c @@ -89,3 +89,4 @@ module_exit(exit_rc_map_mecool_kii_pro) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt "); +MODULE_DESCRIPTION("Medion X10 RF remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-minix-neo.c b/drivers/media/rc/keymaps/rc-minix-neo.c index 9165af548ff1d..ce16e964e72e6 100644 --- a/drivers/media/rc/keymaps/rc-minix-neo.c +++ b/drivers/media/rc/keymaps/rc-minix-neo.c @@ -53,3 +53,4 @@ module_exit(exit_rc_map_minix_neo) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt "); +MODULE_DESCRIPTION("MSI DIGIVOX mini II remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-iii.c b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c index 6129d3e925e5c..1250cde3367de 100644 --- a/drivers/media/rc/keymaps/rc-msi-digivox-iii.c +++ b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c @@ -71,3 +71,4 @@ module_exit(exit_rc_map_msi_digivox_iii) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("MSI DIGIVOX mini III remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c index 42270a7ef3ee9..648bac448f293 100644 --- a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c +++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c @@ -117,3 +117,4 @@ module_exit(exit_rc_map_msi_tvanywhere_plus) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("MSI TV@nywhere Plus remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c index 45793c641009f..b59af39ba0052 100644 --- a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c +++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c @@ -63,3 +63,4 @@ module_exit(exit_rc_map_msi_tvanywhere) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("MSI TV@nywhere MASTER remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-nebula.c b/drivers/media/rc/keymaps/rc-nebula.c index 2dc6061f69b37..23b75269d3070 100644 --- a/drivers/media/rc/keymaps/rc-nebula.c +++ b/drivers/media/rc/keymaps/rc-nebula.c @@ -90,3 +90,4 @@ module_exit(exit_rc_map_nebula) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("nebula remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c index b12c54d47db3d..94340a1864a02 100644 --- a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c +++ b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c @@ -151,3 +151,4 @@ module_exit(exit_rc_map_nec_terratec_cinergy_xs) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Terratec Cinergy Hybrid T USB XS FM remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-norwood.c b/drivers/media/rc/keymaps/rc-norwood.c index acd5b1ccf8d03..da00003a5e798 100644 --- a/drivers/media/rc/keymaps/rc-norwood.c +++ b/drivers/media/rc/keymaps/rc-norwood.c @@ -79,3 +79,4 @@ module_exit(exit_rc_map_norwood) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Norwood Micro (non-Pro) TV Tuner remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-npgtech.c b/drivers/media/rc/keymaps/rc-npgtech.c index 98a755e8bc181..6f4412922e0cf 100644 --- a/drivers/media/rc/keymaps/rc-npgtech.c +++ b/drivers/media/rc/keymaps/rc-npgtech.c @@ -74,3 +74,4 @@ module_exit(exit_rc_map_npgtech) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("npgtech remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-odroid.c b/drivers/media/rc/keymaps/rc-odroid.c index c6fbb64b5c417..0353229a4915b 100644 --- a/drivers/media/rc/keymaps/rc-odroid.c +++ b/drivers/media/rc/keymaps/rc-odroid.c @@ -52,3 +52,4 @@ module_exit(exit_rc_map_odroid) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt "); +MODULE_DESCRIPTION("rc6 MCE remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c index 33bb458b81fd1..088ead8f736bd 100644 --- a/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c +++ b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c @@ -72,3 +72,4 @@ module_exit(exit_rc_map_real_audio_220_32_keys) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Zogis Real Audio 220 - 32 keys remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-reddo.c b/drivers/media/rc/keymaps/rc-reddo.c index b70390d19e781..af50d1ca4b15d 100644 --- a/drivers/media/rc/keymaps/rc-reddo.c +++ b/drivers/media/rc/keymaps/rc-reddo.c @@ -71,3 +71,4 @@ module_exit(exit_rc_map_reddo) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("reddo remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-snapstream-firefly.c b/drivers/media/rc/keymaps/rc-snapstream-firefly.c index e3d5bff3bd9e5..826f44595e701 100644 --- a/drivers/media/rc/keymaps/rc-snapstream-firefly.c +++ b/drivers/media/rc/keymaps/rc-snapstream-firefly.c @@ -92,3 +92,4 @@ module_exit(exit_rc_map_snapstream_firefly) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Anssi Hannula "); +MODULE_DESCRIPTION("SnapStream Firefly X10 RF remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-streamzap.c b/drivers/media/rc/keymaps/rc-streamzap.c index 6684e2e86bc96..b82c3cdfca3b7 100644 --- a/drivers/media/rc/keymaps/rc-streamzap.c +++ b/drivers/media/rc/keymaps/rc-streamzap.c @@ -75,3 +75,4 @@ module_exit(exit_rc_map_streamzap) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jarod Wilson "); +MODULE_DESCRIPTION("Streamzap remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-su3000.c b/drivers/media/rc/keymaps/rc-su3000.c index 64cfc01aa48f5..a333ade3b1d2a 100644 --- a/drivers/media/rc/keymaps/rc-su3000.c +++ b/drivers/media/rc/keymaps/rc-su3000.c @@ -69,3 +69,4 @@ module_exit(exit_rc_map_su3000) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Evgeny Plehov "); +MODULE_DESCRIPTION("Geniatech HDStar remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-tanix-tx3mini.c b/drivers/media/rc/keymaps/rc-tanix-tx3mini.c index d486cd69afb2a..b5d77a0c94ed3 100644 --- a/drivers/media/rc/keymaps/rc-tanix-tx3mini.c +++ b/drivers/media/rc/keymaps/rc-tanix-tx3mini.c @@ -75,3 +75,4 @@ module_exit(exit_rc_map_tanix_tx3mini) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt "); +MODULE_DESCRIPTION("Tanix TX3 mini STB remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-tanix-tx5max.c b/drivers/media/rc/keymaps/rc-tanix-tx5max.c index 59aaabed80dd3..91db9017845a4 100644 --- a/drivers/media/rc/keymaps/rc-tanix-tx5max.c +++ b/drivers/media/rc/keymaps/rc-tanix-tx5max.c @@ -66,3 +66,4 @@ module_exit(exit_rc_map_tanix_tx5max) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt "); +MODULE_DESCRIPTION("Tanix TX5 max STB remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-tbs-nec.c b/drivers/media/rc/keymaps/rc-tbs-nec.c index 420980925f298..426c767c907f9 100644 --- a/drivers/media/rc/keymaps/rc-tbs-nec.c +++ b/drivers/media/rc/keymaps/rc-tbs-nec.c @@ -69,3 +69,4 @@ module_exit(exit_rc_map_tbs_nec) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("tbs-nec remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-technisat-ts35.c b/drivers/media/rc/keymaps/rc-technisat-ts35.c index 9a917ea0ceba8..07d5e0884eb94 100644 --- a/drivers/media/rc/keymaps/rc-technisat-ts35.c +++ b/drivers/media/rc/keymaps/rc-technisat-ts35.c @@ -70,3 +70,4 @@ module_init(init_rc_map) module_exit(exit_rc_map) MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("TechniSat TS35 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-technisat-usb2.c b/drivers/media/rc/keymaps/rc-technisat-usb2.c index 942100686c826..74ac89d379661 100644 --- a/drivers/media/rc/keymaps/rc-technisat-usb2.c +++ b/drivers/media/rc/keymaps/rc-technisat-usb2.c @@ -88,3 +88,4 @@ module_exit(exit_rc_map) MODULE_AUTHOR("Patrick Boettcher "); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("TechniSat TS35 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c index da06f844d8fb3..d448913081937 100644 --- a/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c +++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c @@ -82,3 +82,4 @@ module_init(init_rc_map_terratec_cinergy_c_pci); module_exit(exit_rc_map_terratec_cinergy_c_pci); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Terratec Cinergy C PCI remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c index a1844b531572d..dbbb1ba0247b2 100644 --- a/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c +++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c @@ -80,3 +80,4 @@ module_init(init_rc_map_terratec_cinergy_s2_hd); module_exit(exit_rc_map_terratec_cinergy_s2_hd); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Terratec Cinergy S2 HD remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c index fe587e3f02400..a9452d581339f 100644 --- a/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c +++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c @@ -86,3 +86,4 @@ module_exit(exit_rc_map_terratec_cinergy_xs) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Terratec Cinergy Hybrid T USB XS remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-terratec-slim-2.c b/drivers/media/rc/keymaps/rc-terratec-slim-2.c index a54a59f903131..ea259d88769b9 100644 --- a/drivers/media/rc/keymaps/rc-terratec-slim-2.c +++ b/drivers/media/rc/keymaps/rc-terratec-slim-2.c @@ -58,3 +58,4 @@ module_exit(exit_rc_map_terratec_slim_2) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("TerraTec slim remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-terratec-slim.c b/drivers/media/rc/keymaps/rc-terratec-slim.c index 146e3a3480dc4..bb40cbd58ebe2 100644 --- a/drivers/media/rc/keymaps/rc-terratec-slim.c +++ b/drivers/media/rc/keymaps/rc-terratec-slim.c @@ -65,3 +65,4 @@ module_exit(exit_rc_map_terratec_slim) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("TerraTec slim remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-tevii-nec.c b/drivers/media/rc/keymaps/rc-tevii-nec.c index 5b96e9a38e9d8..ee7f8014742b2 100644 --- a/drivers/media/rc/keymaps/rc-tevii-nec.c +++ b/drivers/media/rc/keymaps/rc-tevii-nec.c @@ -82,3 +82,4 @@ module_exit(exit_rc_map_tevii_nec) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("tevii-nec remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-tivo.c b/drivers/media/rc/keymaps/rc-tivo.c index c51606a3be681..c02b8c8abd5cf 100644 --- a/drivers/media/rc/keymaps/rc-tivo.c +++ b/drivers/media/rc/keymaps/rc-tivo.c @@ -93,3 +93,4 @@ module_exit(exit_rc_map_tivo) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jarod Wilson "); +MODULE_DESCRIPTION("TiVo remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c b/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c index 40b773ba45b95..290d1cc8577c8 100644 --- a/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c +++ b/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c @@ -71,3 +71,4 @@ module_exit(exit_rc_map_total_media_in_hand_02) MODULE_LICENSE("GPL"); MODULE_AUTHOR(" Alfredo J. Delaiti "); +MODULE_DESCRIPTION("Total Media In Hand_02 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-total-media-in-hand.c b/drivers/media/rc/keymaps/rc-total-media-in-hand.c index 2144db485d83a..7f4b31b98f350 100644 --- a/drivers/media/rc/keymaps/rc-total-media-in-hand.c +++ b/drivers/media/rc/keymaps/rc-total-media-in-hand.c @@ -71,3 +71,4 @@ module_exit(exit_rc_map_total_media_in_hand) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Total Media In Hand remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-trekstor.c b/drivers/media/rc/keymaps/rc-trekstor.c index e938e0da51a69..ff01de5509042 100644 --- a/drivers/media/rc/keymaps/rc-trekstor.c +++ b/drivers/media/rc/keymaps/rc-trekstor.c @@ -66,3 +66,4 @@ module_exit(exit_rc_map_trekstor) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("TrekStor remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-tt-1500.c b/drivers/media/rc/keymaps/rc-tt-1500.c index ff70aab13b486..eb8d7fc5061af 100644 --- a/drivers/media/rc/keymaps/rc-tt-1500.c +++ b/drivers/media/rc/keymaps/rc-tt-1500.c @@ -76,3 +76,4 @@ module_exit(exit_rc_map_tt_1500) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Technotrend 1500 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c b/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c index 5fc696d9e5839..8e5cf8eb0db9f 100644 --- a/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c +++ b/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c @@ -92,3 +92,4 @@ module_init(init_rc_map_twinhan_dtv_cab_ci); module_exit(exit_rc_map_twinhan_dtv_cab_ci); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Twinhan DTV CAB CI remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-twinhan1027.c b/drivers/media/rc/keymaps/rc-twinhan1027.c index e1cdcfa792dc4..411ce3c8cbd06 100644 --- a/drivers/media/rc/keymaps/rc-twinhan1027.c +++ b/drivers/media/rc/keymaps/rc-twinhan1027.c @@ -87,3 +87,4 @@ module_exit(exit_rc_map_twinhan_vp1027) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Sergey Ivanov <123kash@gmail.com>"); +MODULE_DESCRIPTION("twinhan1027 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-vega-s9x.c b/drivers/media/rc/keymaps/rc-vega-s9x.c index bf210c4dc5357..40fbf408bf65f 100644 --- a/drivers/media/rc/keymaps/rc-vega-s9x.c +++ b/drivers/media/rc/keymaps/rc-vega-s9x.c @@ -52,3 +52,4 @@ module_exit(exit_rc_map_vega_s9x) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt "); +MODULE_DESCRIPTION("videomate-m1f remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-videomate-s350.c b/drivers/media/rc/keymaps/rc-videomate-s350.c index a867d7a08055c..281cc747229fd 100644 --- a/drivers/media/rc/keymaps/rc-videomate-s350.c +++ b/drivers/media/rc/keymaps/rc-videomate-s350.c @@ -79,3 +79,4 @@ module_exit(exit_rc_map_videomate_s350) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("videomate-s350 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c index fdc3b0e1350f3..829842425faea 100644 --- a/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c +++ b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c @@ -81,3 +81,4 @@ module_exit(exit_rc_map_videomate_tv_pvr) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("videomate-tv-pvr remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-videostrong-kii-pro.c b/drivers/media/rc/keymaps/rc-videostrong-kii-pro.c index 414d4d231e7ed..10cbc2c781d21 100644 --- a/drivers/media/rc/keymaps/rc-videostrong-kii-pro.c +++ b/drivers/media/rc/keymaps/rc-videostrong-kii-pro.c @@ -81,3 +81,4 @@ module_exit(exit_rc_map_kii_pro) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mohammad Rasim "); +MODULE_DESCRIPTION("Videostrong KII Pro STB remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-wetek-hub.c b/drivers/media/rc/keymaps/rc-wetek-hub.c index b5a21aff45f5c..591ec20399f4b 100644 --- a/drivers/media/rc/keymaps/rc-wetek-hub.c +++ b/drivers/media/rc/keymaps/rc-wetek-hub.c @@ -51,3 +51,4 @@ module_exit(exit_rc_map_wetek_hub) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt "); +MODULE_DESCRIPTION("WeTek Hub STB remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-wetek-play2.c b/drivers/media/rc/keymaps/rc-wetek-play2.c index bbbb11fa3c11d..ce3b1029df231 100644 --- a/drivers/media/rc/keymaps/rc-wetek-play2.c +++ b/drivers/media/rc/keymaps/rc-wetek-play2.c @@ -91,3 +91,4 @@ module_exit(exit_rc_map_wetek_play2) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt "); MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("zx-irdec remote controller keytable"); -- GitLab From a1766a4fd83befa0b34d932d532e7ebb7fab1fa7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 22 Sep 2023 14:38:07 +0200 Subject: [PATCH 0513/1451] media: imon: fix access to invalid resource for the second interface imon driver probes two USB interfaces, and at the probe of the second interface, the driver assumes blindly that the first interface got bound with the same imon driver. It's usually true, but it's still possible that the first interface is bound with another driver via a malformed descriptor. Then it may lead to a memory corruption, as spotted by syzkaller; imon driver accesses the data from drvdata as struct imon_context object although it's a completely different one that was assigned by another driver. This patch adds a sanity check -- whether the first interface is really bound with the imon driver or not -- for avoiding the problem above at the probe time. Reported-by: syzbot+59875ffef5cb9c9b29e9@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/000000000000a838aa0603cc74d6@google.com/ Tested-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20230922005152.163640-1-ricardo@marliere.net Signed-off-by: Takashi Iwai Signed-off-by: Sean Young Signed-off-by: Hans Verkuil --- drivers/media/rc/imon.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 74546f7e34691..5719dda6e0f0e 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -2427,6 +2427,12 @@ static int imon_probe(struct usb_interface *interface, goto fail; } + if (first_if->dev.driver != interface->dev.driver) { + dev_err(&interface->dev, "inconsistent driver matching\n"); + ret = -EINVAL; + goto fail; + } + if (ifnum == 0) { ictx = imon_init_intf0(interface, id); if (!ictx) { -- GitLab From 6ccfe1e3971283fb5da0fef8c202f9998a5540fb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 6 Oct 2023 12:08:42 +0200 Subject: [PATCH 0514/1451] staging: media: atomisp: drop check for reentrant .s_stream() The subdev .s_stream() operation shall not be called to start streaming on an already started subdev, or stop streaming on a stopped subdev. Remove the check that guards against that condition. Also fixes a smatch warning: drivers/staging/media/atomisp/i2c/atomisp-gc0310.c:446 gc0310_s_stream() warn: missing error code 'ret' Signed-off-by: Hans Verkuil CC: Hans de Goede Reviewed-by: Hans de Goede --- drivers/staging/media/atomisp/i2c/atomisp-gc0310.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c index c438accb0472b..58cddf11c9ab6 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c @@ -441,11 +441,6 @@ static int gc0310_s_stream(struct v4l2_subdev *sd, int enable) dev_dbg(&client->dev, "%s S enable=%d\n", __func__, enable); mutex_lock(&dev->input_lock); - if (dev->is_streaming == enable) { - dev_warn(&client->dev, "stream already %s\n", enable ? "started" : "stopped"); - goto error_unlock; - } - if (enable) { ret = pm_runtime_get_sync(&client->dev); if (ret < 0) @@ -497,7 +492,6 @@ static int gc0310_s_stream(struct v4l2_subdev *sd, int enable) error_power_down: pm_runtime_put(&client->dev); dev->is_streaming = false; -error_unlock: mutex_unlock(&dev->input_lock); return ret; } -- GitLab From f06acbe3398c4141939c6362301220d2fdfba805 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 6 Oct 2023 12:08:48 +0200 Subject: [PATCH 0515/1451] media: i2c: tc358746: check fmt validity Check if the format was really found. Fixes smatch warning: drivers/media/i2c/tc358746.c:790 tc358746_set_fmt() error: 'fmt' dereferencing possible ERR_PTR() Signed-off-by: Hans Verkuil CC: Sakari Ailus Reviewed-by: Sakari Ailus --- drivers/media/i2c/tc358746.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c index 566f5eaddd572..ce612a47ba848 100644 --- a/drivers/media/i2c/tc358746.c +++ b/drivers/media/i2c/tc358746.c @@ -784,8 +784,12 @@ static int tc358746_set_fmt(struct v4l2_subdev *sd, sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, TC358746_SINK); fmt = tc358746_get_format_by_code(format->pad, format->format.code); - if (IS_ERR(fmt)) + if (IS_ERR(fmt)) { fmt = tc358746_get_format_by_code(format->pad, tc358746_def_fmt.code); + // Can't happen, but just in case... + if (WARN_ON(IS_ERR(fmt))) + return -EINVAL; + } format->format.code = fmt->code; format->format.field = V4L2_FIELD_NONE; -- GitLab From 545668480f7b89918f2406c36f9ae8813ac26887 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 6 Oct 2023 12:08:44 +0200 Subject: [PATCH 0516/1451] staging: media: atomisp: improve unwinding This fixes two smatch warnings: drivers/staging/media/atomisp/pci/atomisp_cmd.c:2779 atomisp_cp_dvs_6axis_config() warn: missing unwind goto? drivers/staging/media/atomisp/pci/atomisp_cmd.c:2878 atomisp_cp_morph_table() warn: missing unwind goto? Signed-off-by: Hans Verkuil CC: Hans de Goede Reviewed-by: Hans de Goede --- .../staging/media/atomisp/pci/atomisp_cmd.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c index a54be2d20c587..759233a7ba505 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c @@ -2771,12 +2771,16 @@ int atomisp_cp_dvs_6axis_config(struct atomisp_sub_device *asd, css_param->dvs_6axis = NULL; dvs_6axis_config = ia_css_dvs2_6axis_config_allocate(stream); - if (!dvs_6axis_config) - return -ENOMEM; + if (!dvs_6axis_config) { + ret = -ENOMEM; + goto error; + } } else if (!dvs_6axis_config) { dvs_6axis_config = ia_css_dvs2_6axis_config_allocate(stream); - if (!dvs_6axis_config) - return -ENOMEM; + if (!dvs_6axis_config) { + ret = -ENOMEM; + goto error; + } } dvs_6axis_config->exp_id = source_6axis_config->exp_id; @@ -2874,8 +2878,10 @@ int atomisp_cp_morph_table(struct atomisp_sub_device *asd, morph_table = atomisp_css_morph_table_allocate( source_morph_table->width, source_morph_table->height); - if (!morph_table) - return -ENOMEM; + if (!morph_table) { + ret = -ENOMEM; + goto error; + } for (i = 0; i < IA_CSS_MORPH_TABLE_NUM_PLANES; i++) { if (copy_from_compatible(morph_table->coordinates_x[i], -- GitLab From 4f7efc71891462ab7606da7039f480d7c1584a13 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Fri, 6 Oct 2023 12:54:25 +0100 Subject: [PATCH 0517/1451] media: sharp: fix sharp encoding The Sharp protocol[1] encoding has incorrect timings for bit space. [1] https://www.sbprojects.net/knowledge/ir/sharp.php Fixes: d35afc5fe097 ("[media] rc: ir-sharp-decoder: Add encode capability") Cc: stable@vger.kernel.org Reported-by: Joe Ferner Closes: https://sourceforge.net/p/lirc/mailman/message/38604507/ Signed-off-by: Sean Young Signed-off-by: Hans Verkuil --- drivers/media/rc/ir-sharp-decoder.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c index 3d8488c39c561..3311099cbd573 100644 --- a/drivers/media/rc/ir-sharp-decoder.c +++ b/drivers/media/rc/ir-sharp-decoder.c @@ -15,7 +15,9 @@ #define SHARP_UNIT 40 /* us */ #define SHARP_BIT_PULSE (8 * SHARP_UNIT) /* 320us */ #define SHARP_BIT_0_PERIOD (25 * SHARP_UNIT) /* 1ms (680us space) */ -#define SHARP_BIT_1_PERIOD (50 * SHARP_UNIT) /* 2ms (1680ms space) */ +#define SHARP_BIT_1_PERIOD (50 * SHARP_UNIT) /* 2ms (1680us space) */ +#define SHARP_BIT_0_SPACE (17 * SHARP_UNIT) /* 680us space */ +#define SHARP_BIT_1_SPACE (42 * SHARP_UNIT) /* 1680us space */ #define SHARP_ECHO_SPACE (1000 * SHARP_UNIT) /* 40 ms */ #define SHARP_TRAILER_SPACE (125 * SHARP_UNIT) /* 5 ms (even longer) */ @@ -168,8 +170,8 @@ static const struct ir_raw_timings_pd ir_sharp_timings = { .header_pulse = 0, .header_space = 0, .bit_pulse = SHARP_BIT_PULSE, - .bit_space[0] = SHARP_BIT_0_PERIOD, - .bit_space[1] = SHARP_BIT_1_PERIOD, + .bit_space[0] = SHARP_BIT_0_SPACE, + .bit_space[1] = SHARP_BIT_1_SPACE, .trailer_pulse = SHARP_BIT_PULSE, .trailer_space = SHARP_ECHO_SPACE, .msb_first = 1, -- GitLab From c8a489f820179fb12251e262b50303c29de991ac Mon Sep 17 00:00:00 2001 From: Sean Young Date: Fri, 6 Oct 2023 22:31:52 +0100 Subject: [PATCH 0518/1451] media: lirc: drop trailing space from scancode transmit When transmitting, infrared drivers expect an odd number of samples; iow without a trailing space. No problems have been observed so far, so this is just belt and braces. Fixes: 9b6192589be7 ("media: lirc: implement scancode sending") Cc: stable@vger.kernel.org Signed-off-by: Sean Young Signed-off-by: Hans Verkuil --- drivers/media/rc/lirc_dev.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 043d23aaa3cbc..a537734832c50 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -276,7 +276,11 @@ static ssize_t lirc_transmit(struct file *file, const char __user *buf, if (ret < 0) goto out_kfree_raw; - count = ret; + /* drop trailing space */ + if (!(ret % 2)) + count = ret - 1; + else + count = ret; txbuf = kmalloc_array(count, sizeof(unsigned int), GFP_KERNEL); if (!txbuf) { -- GitLab From 3cbb42827d0d2bb509e765df6d4d2b483f870bd8 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Thu, 24 Aug 2023 21:55:12 +0800 Subject: [PATCH 0519/1451] watchdog: at91sam9_wdt: Use the devm_clk_get_enabled() helper function The devm_clk_get_enabled() helper: - calls devm_clk_get() - calls clk_prepare_enable() and registers what is needed in order to call clk_disable_unprepare() when needed, as a managed resource. This simplifies the code. Signed-off-by: Jinjie Ruan Reviewed-by: Claudiu Beznea Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20230824135514.2661364-2-ruanjinjie@huawei.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/at91sam9_wdt.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c index fed7be2464420..b111b28acb948 100644 --- a/drivers/watchdog/at91sam9_wdt.c +++ b/drivers/watchdog/at91sam9_wdt.c @@ -348,25 +348,21 @@ static int __init at91wdt_probe(struct platform_device *pdev) if (IS_ERR(wdt->base)) return PTR_ERR(wdt->base); - wdt->sclk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(wdt->sclk)) - return PTR_ERR(wdt->sclk); - - err = clk_prepare_enable(wdt->sclk); - if (err) { + wdt->sclk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(wdt->sclk)) { dev_err(&pdev->dev, "Could not enable slow clock\n"); - return err; + return PTR_ERR(wdt->sclk); } if (pdev->dev.of_node) { err = of_at91wdt_init(pdev->dev.of_node, wdt); if (err) - goto err_clk; + return err; } err = at91_wdt_init(pdev, wdt); if (err) - goto err_clk; + return err; platform_set_drvdata(pdev, wdt); @@ -374,11 +370,6 @@ static int __init at91wdt_probe(struct platform_device *pdev) wdt->wdd.timeout, wdt->nowayout); return 0; - -err_clk: - clk_disable_unprepare(wdt->sclk); - - return err; } static int __exit at91wdt_remove(struct platform_device *pdev) @@ -388,7 +379,6 @@ static int __exit at91wdt_remove(struct platform_device *pdev) pr_warn("I quit now, hardware will probably reboot!\n"); del_timer(&wdt->timer); - clk_disable_unprepare(wdt->sclk); return 0; } -- GitLab From c51a6977bd9560d7ef2ed35353b328f076e8a591 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Thu, 24 Aug 2023 21:55:13 +0800 Subject: [PATCH 0520/1451] watchdog: ath79_wdt: Use the devm_clk_get_enabled() helper function The devm_clk_get_enabled() helper: - calls devm_clk_get() - calls clk_prepare_enable() and registers what is needed in order to call clk_disable_unprepare() when needed, as a managed resource. This simplifies the code. Signed-off-by: Jinjie Ruan Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20230824135514.2661364-3-ruanjinjie@huawei.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/ath79_wdt.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/watchdog/ath79_wdt.c b/drivers/watchdog/ath79_wdt.c index b7b7050604388..e5cc30622b12f 100644 --- a/drivers/watchdog/ath79_wdt.c +++ b/drivers/watchdog/ath79_wdt.c @@ -257,19 +257,13 @@ static int ath79_wdt_probe(struct platform_device *pdev) if (IS_ERR(wdt_base)) return PTR_ERR(wdt_base); - wdt_clk = devm_clk_get(&pdev->dev, "wdt"); + wdt_clk = devm_clk_get_enabled(&pdev->dev, "wdt"); if (IS_ERR(wdt_clk)) return PTR_ERR(wdt_clk); - err = clk_prepare_enable(wdt_clk); - if (err) - return err; - wdt_freq = clk_get_rate(wdt_clk); - if (!wdt_freq) { - err = -EINVAL; - goto err_clk_disable; - } + if (!wdt_freq) + return -EINVAL; max_timeout = (0xfffffffful / wdt_freq); if (timeout < 1 || timeout > max_timeout) { @@ -286,20 +280,15 @@ static int ath79_wdt_probe(struct platform_device *pdev) if (err) { dev_err(&pdev->dev, "unable to register misc device, err=%d\n", err); - goto err_clk_disable; + return err; } return 0; - -err_clk_disable: - clk_disable_unprepare(wdt_clk); - return err; } static void ath79_wdt_remove(struct platform_device *pdev) { misc_deregister(&ath79_wdt_miscdev); - clk_disable_unprepare(wdt_clk); } static void ath79_wdt_shutdown(struct platform_device *pdev) -- GitLab From bdb970186d156eb596f8f16f6e8467cdd5d57a70 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Thu, 24 Aug 2023 21:55:14 +0800 Subject: [PATCH 0521/1451] watchdog: sunplus: Use the devm_clk_get_enabled() helper function The devm_clk_get_enabled() helper: - calls devm_clk_get() - calls clk_prepare_enable() and registers what is needed in order to call clk_disable_unprepare() when needed, as a managed resource. This simplifies the code and avoids the need of a dedicated function used with devm_add_action_or_reset(). Signed-off-by: Jinjie Ruan Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20230824135514.2661364-4-ruanjinjie@huawei.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/sunplus_wdt.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/drivers/watchdog/sunplus_wdt.c b/drivers/watchdog/sunplus_wdt.c index e2d8c532bcb1a..9d3ca848e8b62 100644 --- a/drivers/watchdog/sunplus_wdt.c +++ b/drivers/watchdog/sunplus_wdt.c @@ -136,11 +136,6 @@ static const struct watchdog_ops sp_wdt_ops = { .restart = sp_wdt_restart, }; -static void sp_clk_disable_unprepare(void *data) -{ - clk_disable_unprepare(data); -} - static void sp_reset_control_assert(void *data) { reset_control_assert(data); @@ -156,17 +151,9 @@ static int sp_wdt_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - priv->clk = devm_clk_get(dev, NULL); + priv->clk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(priv->clk)) - return dev_err_probe(dev, PTR_ERR(priv->clk), "Failed to get clock\n"); - - ret = clk_prepare_enable(priv->clk); - if (ret) - return dev_err_probe(dev, ret, "Failed to enable clock\n"); - - ret = devm_add_action_or_reset(dev, sp_clk_disable_unprepare, priv->clk); - if (ret) - return ret; + return dev_err_probe(dev, PTR_ERR(priv->clk), "Failed to enable clock\n"); /* The timer and watchdog shared the STC reset */ priv->rstc = devm_reset_control_get_shared(dev, NULL); -- GitLab From 15f0f6d2ee05392ce05244a1aadc8b564099672d Mon Sep 17 00:00:00 2001 From: Srinivas Neeli Date: Wed, 30 Aug 2023 15:58:25 +0530 Subject: [PATCH 0522/1451] watchdog: of_xilinx_wdt: Remove unnecessary clock disable call in the remove path There is a mismatch in axi clock enable and disable calls. The axi clock is enabled and disabled by the probe function, then it is again disabled in the remove path. So observed the call trace while removing the module. Use the clk_enable() and devm_clk_get_prepared() functions instead of devm_clk_get_enable() to avoid an extra clock disable call from the remove path. Call trace: clk_core_disable+0xb0/0xc0 clk_disable+0x30/0x4c clk_disable_unprepare+0x18/0x30 devm_clk_release+0x24/0x40 devres_release_all+0xc8/0x190 device_unbind_cleanup+0x18/0x6c device_release_driver_internal+0x20c/0x250 device_release_driver+0x18/0x24 bus_remove_device+0x124/0x130 device_del+0x174/0x440 Fixes: b6bc41645547 ("watchdog: of_xilinx_wdt: Add support for reading freq via CCF") Signed-off-by: Srinivas Neeli Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20230901070929.1317982-1-ruanjinjie@huawei.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/of_xilinx_wdt.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c index 05657dc1d36a0..352853e6fe712 100644 --- a/drivers/watchdog/of_xilinx_wdt.c +++ b/drivers/watchdog/of_xilinx_wdt.c @@ -187,7 +187,7 @@ static int xwdt_probe(struct platform_device *pdev) watchdog_set_nowayout(xilinx_wdt_wdd, enable_once); - xdev->clk = devm_clk_get_enabled(dev, NULL); + xdev->clk = devm_clk_get_prepared(dev, NULL); if (IS_ERR(xdev->clk)) { if (PTR_ERR(xdev->clk) != -ENOENT) return PTR_ERR(xdev->clk); @@ -218,18 +218,25 @@ static int xwdt_probe(struct platform_device *pdev) spin_lock_init(&xdev->spinlock); watchdog_set_drvdata(xilinx_wdt_wdd, xdev); + rc = clk_enable(xdev->clk); + if (rc) { + dev_err(dev, "unable to enable clock\n"); + return rc; + } + rc = xwdt_selftest(xdev); if (rc == XWT_TIMER_FAILED) { dev_err(dev, "SelfTest routine error\n"); + clk_disable(xdev->clk); return rc; } + clk_disable(xdev->clk); + rc = devm_watchdog_register_device(dev, xilinx_wdt_wdd); if (rc) return rc; - clk_disable(xdev->clk); - dev_info(dev, "Xilinx Watchdog Timer with timeout %ds\n", xilinx_wdt_wdd->timeout); -- GitLab From db7673e6d5783a8664840b9218f58b5b836603ce Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Fri, 1 Sep 2023 15:09:29 +0800 Subject: [PATCH 0523/1451] Watchdog: marvell_gti_wdt: Remove redundant dev_err_probe() for platform_get_irq() Since commit 7723f4c5ecdb ("driver core: platform: Add an error message to platform_get_irq*()"), there is no need to call the dev_err_probe() function directly to print a custom message when handling an error from platform_get_irq() function as it is going to display an appropriate error message in case of a failure. Fixes: ef9e7fe2c890 ("Watchdog: Add marvell GTI watchdog driver") Signed-off-by: Jinjie Ruan Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20230901070929.1317982-1-ruanjinjie@huawei.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/marvell_gti_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/marvell_gti_wdt.c b/drivers/watchdog/marvell_gti_wdt.c index d7eb8286e11ec..d5a1ff91d4233 100644 --- a/drivers/watchdog/marvell_gti_wdt.c +++ b/drivers/watchdog/marvell_gti_wdt.c @@ -308,7 +308,7 @@ static int gti_wdt_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) - return dev_err_probe(&pdev->dev, irq, "IRQ resource not found\n"); + return irq; err = devm_request_irq(dev, irq, gti_wdt_interrupt, 0, pdev->name, &priv->wdev); -- GitLab From 5c77ebcd05acf3789949c8a387df72381d949ca2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 9 Oct 2023 16:13:40 -0500 Subject: [PATCH 0524/1451] remoteproc: st: Use device_get_match_data() Use preferred device_get_match_data() instead of of_match_device() to get the driver match data. With this, adjust the includes to explicitly include the correct headers. Signed-off-by: Rob Herring Reviewed-by: Patrice Chotard Link: https://lore.kernel.org/r/20231009211356.3242037-10-robh@kernel.org Signed-off-by: Mathieu Poirier --- drivers/remoteproc/st_remoteproc.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c index e3ce01d98b4c7..b0638f984842e 100644 --- a/drivers/remoteproc/st_remoteproc.c +++ b/drivers/remoteproc/st_remoteproc.c @@ -16,10 +16,9 @@ #include #include #include -#include -#include #include #include +#include #include #include #include @@ -341,7 +340,6 @@ static int st_rproc_parse_dt(struct platform_device *pdev) static int st_rproc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - const struct of_device_id *match; struct st_rproc *ddata; struct device_node *np = dev->of_node; struct rproc *rproc; @@ -349,19 +347,15 @@ static int st_rproc_probe(struct platform_device *pdev) int enabled; int ret, i; - match = of_match_device(st_rproc_match, dev); - if (!match || !match->data) { - dev_err(dev, "No device match found\n"); - return -ENODEV; - } - rproc = rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata)); if (!rproc) return -ENOMEM; rproc->has_iommu = false; ddata = rproc->priv; - ddata->config = (struct st_rproc_config *)match->data; + ddata->config = (struct st_rproc_config *)device_get_match_data(dev); + if (!ddata->config) + goto free_rproc; platform_set_drvdata(pdev, rproc); -- GitLab From 06affa7a002677942340a6127a8808ad5b5deafc Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 7 Oct 2023 17:05:42 -0300 Subject: [PATCH 0525/1451] staging: media: ipu3: remove ftrace-like logging This patch fixes the following checkpatch.pl warnings in ipu3.c: WARNING: Unnecessary ftrace-like logging - prefer using ftrace + dev_dbg(dev, "enter %s\n", __func__); WARNING: Unnecessary ftrace-like logging - prefer using ftrace + dev_dbg(dev, "leave %s\n", __func__); WARNING: Unnecessary ftrace-like logging - prefer using ftrace + dev_dbg(dev, "enter %s\n", __func__); WARNING: Unnecessary ftrace-like logging - prefer using ftrace + dev_dbg(dev, "leave %s\n", __func__); Fixes: 7fc7af649ca7 ("media: staging/intel-ipu3: Add imgu top level pci device driver") Signed-off-by: Ricardo B. Marliere Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/staging/media/ipu3/ipu3.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/staging/media/ipu3/ipu3.c b/drivers/staging/media/ipu3/ipu3.c index 0c453b37f8c4b..18ca22c3018a2 100644 --- a/drivers/staging/media/ipu3/ipu3.c +++ b/drivers/staging/media/ipu3/ipu3.c @@ -762,7 +762,6 @@ static int __maybe_unused imgu_suspend(struct device *dev) struct pci_dev *pci_dev = to_pci_dev(dev); struct imgu_device *imgu = pci_get_drvdata(pci_dev); - dev_dbg(dev, "enter %s\n", __func__); imgu->suspend_in_stream = imgu_css_is_streaming(&imgu->css); if (!imgu->suspend_in_stream) goto out; @@ -783,7 +782,6 @@ static int __maybe_unused imgu_suspend(struct device *dev) imgu_powerdown(imgu); pm_runtime_force_suspend(dev); out: - dev_dbg(dev, "leave %s\n", __func__); return 0; } @@ -793,8 +791,6 @@ static int __maybe_unused imgu_resume(struct device *dev) int r = 0; unsigned int pipe; - dev_dbg(dev, "enter %s\n", __func__); - if (!imgu->suspend_in_stream) goto out; @@ -821,8 +817,6 @@ static int __maybe_unused imgu_resume(struct device *dev) } out: - dev_dbg(dev, "leave %s\n", __func__); - return r; } -- GitLab From 0b1e6f6a9f73eb4a16a5aadd15bac42ddcb51f88 Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Mon, 9 Oct 2023 19:56:48 +0530 Subject: [PATCH 0526/1451] media: Documentation: ccs: Fix spelling mistake Correct the wrong spelling of 'exposes' in the binner section. Signed-off-by: Umang Jain Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- Documentation/driver-api/media/drivers/ccs/ccs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/driver-api/media/drivers/ccs/ccs.rst b/Documentation/driver-api/media/drivers/ccs/ccs.rst index 0468b9413a318..776eec72bc80a 100644 --- a/Documentation/driver-api/media/drivers/ccs/ccs.rst +++ b/Documentation/driver-api/media/drivers/ccs/ccs.rst @@ -30,7 +30,7 @@ that purpose, selection target ``V4L2_SEL_TGT_COMPOSE`` is supported on the sink pad (0). Additionally, if a device has no scaler or digital crop functionality, the -source pad (1) expses another digital crop selection rectangle that can only +source pad (1) exposes another digital crop selection rectangle that can only crop at the end of the lines and frames. Scaler -- GitLab From c49f2a696272303ce3dd3684c984b025ca6dad82 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Mon, 9 Oct 2023 18:39:27 +0530 Subject: [PATCH 0527/1451] media: dt-bindings: Make sure items in data-lanes are unique The data-lanes property maps the logical lane numbers to the physical lane numbers. The position of an entry is the logical lane number and its value is the physical lane number. Since one physical lane can only map to one logical lane, no number in the list should repeat. Add the uniqueItems constraint on the property to enforce this. Signed-off-by: Pratyush Yadav Tested-by: Julien Massot Reviewed-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Reviewed-by: Maxime Ripard Acked-by: Rob Herring Signed-off-by: Jai Luthra Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- Documentation/devicetree/bindings/media/video-interfaces.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/media/video-interfaces.yaml b/Documentation/devicetree/bindings/media/video-interfaces.yaml index a211d49dc2ac3..26e3e7d7c67ba 100644 --- a/Documentation/devicetree/bindings/media/video-interfaces.yaml +++ b/Documentation/devicetree/bindings/media/video-interfaces.yaml @@ -160,6 +160,7 @@ properties: $ref: /schemas/types.yaml#/definitions/uint32-array minItems: 1 maxItems: 8 + uniqueItems: true items: # Assume up to 9 physical lane indices maximum: 8 -- GitLab From cdb175144aad4983395607d986a482bdb02a9174 Mon Sep 17 00:00:00 2001 From: Jai Luthra Date: Mon, 9 Oct 2023 18:39:28 +0530 Subject: [PATCH 0528/1451] media: dt-bindings: cadence-csi2rx: Add TI compatible string Add a SoC-specific compatible string for TI's integration of this IP in J7 and AM62 line of SoCs. Tested-by: Julien Massot Reviewed-by: Maxime Ripard Reviewed-by: Laurent Pinchart Acked-by: Krzysztof Kozlowski Signed-off-by: Jai Luthra Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- Documentation/devicetree/bindings/media/cdns,csi2rx.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/media/cdns,csi2rx.yaml b/Documentation/devicetree/bindings/media/cdns,csi2rx.yaml index 30a335b107621..2008a47c05806 100644 --- a/Documentation/devicetree/bindings/media/cdns,csi2rx.yaml +++ b/Documentation/devicetree/bindings/media/cdns,csi2rx.yaml @@ -18,6 +18,7 @@ properties: items: - enum: - starfive,jh7110-csi2rx + - ti,j721e-csi2rx - const: cdns,csi2rx reg: -- GitLab From b2701715301a49b53d05c7d43f3fedc3b8743bfc Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Mon, 9 Oct 2023 18:39:29 +0530 Subject: [PATCH 0529/1451] media: cadence: csi2rx: Unregister v4l2 async notifier The notifier is added to the global notifier list when registered. When the module is removed, the struct csi2rx_priv in which the notifier is embedded, is destroyed. As a result the notifier list has a reference to a notifier that no longer exists. This causes invalid memory accesses when the list is iterated over. Similar for when the probe fails. Unregister and clean up the notifier to avoid this. Fixes: 1fc3b37f34f6 ("media: v4l: cadence: Add Cadence MIPI-CSI2 RX driver") Signed-off-by: Pratyush Yadav Tested-by: Julien Massot Reviewed-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Reviewed-by: Maxime Ripard Signed-off-by: Jai Luthra Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/platform/cadence/cdns-csi2rx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index b9d9058e2ce3f..64e472ca3594f 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -479,8 +479,10 @@ static int csi2rx_parse_dt(struct csi2rx_priv *csi2rx) asd = v4l2_async_nf_add_fwnode_remote(&csi2rx->notifier, fwh, struct v4l2_async_connection); of_node_put(ep); - if (IS_ERR(asd)) + if (IS_ERR(asd)) { + v4l2_async_nf_cleanup(&csi2rx->notifier); return PTR_ERR(asd); + } csi2rx->notifier.ops = &csi2rx_notifier_ops; @@ -543,6 +545,7 @@ static int csi2rx_probe(struct platform_device *pdev) return 0; err_cleanup: + v4l2_async_nf_unregister(&csi2rx->notifier); v4l2_async_nf_cleanup(&csi2rx->notifier); err_free_priv: kfree(csi2rx); @@ -553,6 +556,8 @@ static void csi2rx_remove(struct platform_device *pdev) { struct csi2rx_priv *csi2rx = platform_get_drvdata(pdev); + v4l2_async_nf_unregister(&csi2rx->notifier); + v4l2_async_nf_cleanup(&csi2rx->notifier); v4l2_async_unregister_subdev(&csi2rx->subdev); kfree(csi2rx); } -- GitLab From aee5b415c95aa913aa9222bbe13c817c7e67ec85 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Mon, 9 Oct 2023 18:39:30 +0530 Subject: [PATCH 0530/1451] media: cadence: csi2rx: Cleanup media entity properly Call media_entity_cleanup() in probe error path and remove to make sure the media entity is cleaned up properly. Suggested-by: Laurent Pinchart Signed-off-by: Pratyush Yadav Tested-by: Julien Massot Reviewed-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Reviewed-by: Maxime Ripard Signed-off-by: Jai Luthra Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/platform/cadence/cdns-csi2rx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index 64e472ca3594f..399b2f800dc4f 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -547,6 +547,7 @@ static int csi2rx_probe(struct platform_device *pdev) err_cleanup: v4l2_async_nf_unregister(&csi2rx->notifier); v4l2_async_nf_cleanup(&csi2rx->notifier); + media_entity_cleanup(&csi2rx->subdev.entity); err_free_priv: kfree(csi2rx); return ret; @@ -559,6 +560,7 @@ static void csi2rx_remove(struct platform_device *pdev) v4l2_async_nf_unregister(&csi2rx->notifier); v4l2_async_nf_cleanup(&csi2rx->notifier); v4l2_async_unregister_subdev(&csi2rx->subdev); + media_entity_cleanup(&csi2rx->subdev.entity); kfree(csi2rx); } -- GitLab From dbca7b3c412b86e2684542467f2565b52e2f0cb3 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Mon, 9 Oct 2023 18:39:31 +0530 Subject: [PATCH 0531/1451] media: cadence: csi2rx: Add get_fmt and set_fmt pad ops The format is needed to calculate the link speed for the external DPHY configuration. It is not right to query the format from the source subdev. Add get_fmt and set_fmt pad operations so that the format can be configured and correct bpp be selected. Initialize and use the v4l2 subdev active state to keep track of the active formats. Also propagate the new format from the sink pad to all the source pads. Signed-off-by: Pratyush Yadav Tested-by: Julien Massot Reviewed-by: Maxime Ripard Reviewed-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Co-developed-by: Jai Luthra Signed-off-by: Jai Luthra Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/platform/cadence/cdns-csi2rx.c | 96 +++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index 399b2f800dc4f..f9b41451f4a4d 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -61,6 +61,11 @@ enum csi2rx_pads { CSI2RX_PAD_MAX, }; +struct csi2rx_fmt { + u32 code; + u8 bpp; +}; + struct csi2rx_priv { struct device *dev; unsigned int count; @@ -95,6 +100,32 @@ struct csi2rx_priv { int source_pad; }; +static const struct csi2rx_fmt formats[] = { + { .code = MEDIA_BUS_FMT_YUYV8_1X16, .bpp = 16, }, + { .code = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 16, }, + { .code = MEDIA_BUS_FMT_YVYU8_1X16, .bpp = 16, }, + { .code = MEDIA_BUS_FMT_VYUY8_1X16, .bpp = 16, }, + { .code = MEDIA_BUS_FMT_SBGGR8_1X8, .bpp = 8, }, + { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .bpp = 8, }, + { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .bpp = 8, }, + { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 8, }, + { .code = MEDIA_BUS_FMT_SBGGR10_1X10, .bpp = 10, }, + { .code = MEDIA_BUS_FMT_SGBRG10_1X10, .bpp = 10, }, + { .code = MEDIA_BUS_FMT_SGRBG10_1X10, .bpp = 10, }, + { .code = MEDIA_BUS_FMT_SRGGB10_1X10, .bpp = 10, }, +}; + +static const struct csi2rx_fmt *csi2rx_get_fmt_by_code(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(formats); i++) + if (formats[i].code == code) + return &formats[i]; + + return NULL; +} + static inline struct csi2rx_priv *v4l2_subdev_to_csi2rx(struct v4l2_subdev *subdev) { @@ -303,12 +334,68 @@ static int csi2rx_s_stream(struct v4l2_subdev *subdev, int enable) return ret; } +static int csi2rx_set_fmt(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt; + unsigned int i; + + /* No transcoding, source and sink formats must match. */ + if (format->pad != CSI2RX_PAD_SINK) + return v4l2_subdev_get_fmt(subdev, state, format); + + if (!csi2rx_get_fmt_by_code(format->format.code)) + format->format.code = formats[0].code; + + format->format.field = V4L2_FIELD_NONE; + + /* Set sink format */ + fmt = v4l2_subdev_get_pad_format(subdev, state, format->pad); + *fmt = format->format; + + /* Propagate to source formats */ + for (i = CSI2RX_PAD_SOURCE_STREAM0; i < CSI2RX_PAD_MAX; i++) { + fmt = v4l2_subdev_get_pad_format(subdev, state, i); + *fmt = format->format; + } + + return 0; +} + +static int csi2rx_init_cfg(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_format format = { + .pad = CSI2RX_PAD_SINK, + .format = { + .width = 640, + .height = 480, + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, + .ycbcr_enc = V4L2_YCBCR_ENC_601, + .quantization = V4L2_QUANTIZATION_LIM_RANGE, + .xfer_func = V4L2_XFER_FUNC_SRGB, + }, + }; + + return csi2rx_set_fmt(subdev, state, &format); +} + +static const struct v4l2_subdev_pad_ops csi2rx_pad_ops = { + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = csi2rx_set_fmt, + .init_cfg = csi2rx_init_cfg, +}; + static const struct v4l2_subdev_video_ops csi2rx_video_ops = { .s_stream = csi2rx_s_stream, }; static const struct v4l2_subdev_ops csi2rx_subdev_ops = { .video = &csi2rx_video_ops, + .pad = &csi2rx_pad_ops, }; static int csi2rx_async_bound(struct v4l2_async_notifier *notifier, @@ -532,9 +619,13 @@ static int csi2rx_probe(struct platform_device *pdev) if (ret) goto err_cleanup; + ret = v4l2_subdev_init_finalize(&csi2rx->subdev); + if (ret) + goto err_cleanup; + ret = v4l2_async_register_subdev(&csi2rx->subdev); if (ret < 0) - goto err_cleanup; + goto err_free_state; dev_info(&pdev->dev, "Probed CSI2RX with %u/%u lanes, %u streams, %s D-PHY\n", @@ -544,6 +635,8 @@ static int csi2rx_probe(struct platform_device *pdev) return 0; +err_free_state: + v4l2_subdev_cleanup(&csi2rx->subdev); err_cleanup: v4l2_async_nf_unregister(&csi2rx->notifier); v4l2_async_nf_cleanup(&csi2rx->notifier); @@ -560,6 +653,7 @@ static void csi2rx_remove(struct platform_device *pdev) v4l2_async_nf_unregister(&csi2rx->notifier); v4l2_async_nf_cleanup(&csi2rx->notifier); v4l2_async_unregister_subdev(&csi2rx->subdev); + v4l2_subdev_cleanup(&csi2rx->subdev); media_entity_cleanup(&csi2rx->subdev.entity); kfree(csi2rx); } -- GitLab From a91d06f46bf725f97d2bf344294c54bc57686889 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Mon, 9 Oct 2023 18:39:32 +0530 Subject: [PATCH 0532/1451] media: cadence: csi2rx: Configure DPHY using link freq Some platforms like TI's J721E can have the CSI2RX paired with an external DPHY. Use the generic PHY framework to configure the DPHY with the correct link frequency. Signed-off-by: Pratyush Yadav Tested-by: Julien Massot Reviewed-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Reviewed-by: Maxime Ripard Co-developed-by: Jai Luthra Signed-off-by: Jai Luthra Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/platform/cadence/cdns-csi2rx.c | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index f9b41451f4a4d..77e2413c345aa 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -145,8 +145,32 @@ static void csi2rx_reset(struct csi2rx_priv *csi2rx) static int csi2rx_configure_ext_dphy(struct csi2rx_priv *csi2rx) { union phy_configure_opts opts = { }; + struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy; + struct v4l2_subdev_format sd_fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .pad = CSI2RX_PAD_SINK, + }; + const struct csi2rx_fmt *fmt; + s64 link_freq; int ret; + ret = v4l2_subdev_call_state_active(&csi2rx->subdev, pad, get_fmt, + &sd_fmt); + if (ret < 0) + return ret; + + fmt = csi2rx_get_fmt_by_code(sd_fmt.format.code); + + link_freq = v4l2_get_link_freq(csi2rx->source_subdev->ctrl_handler, + fmt->bpp, 2 * csi2rx->num_lanes); + if (link_freq < 0) + return link_freq; + + ret = phy_mipi_dphy_get_default_config_for_hsclk(link_freq, + csi2rx->num_lanes, cfg); + if (ret) + return ret; + ret = phy_power_on(csi2rx->dphy); if (ret) return ret; -- GitLab From 6f28a427a913370300bf116ad900c17bf3dbbf1c Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Mon, 9 Oct 2023 18:39:33 +0530 Subject: [PATCH 0533/1451] media: cadence: csi2rx: Soft reset the streams before starting capture This resets the stream state machines and FIFOs, giving them a clean slate. On J721E if the streams are not reset before starting the capture, the captured frame gets wrapped around vertically on every run after the first. Signed-off-by: Pratyush Yadav Tested-by: Julien Massot Reviewed-by: Laurent Pinchart Reviewed-by: Maxime Ripard Reviewed-by: Tomi Valkeinen Signed-off-by: Jai Luthra Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/platform/cadence/cdns-csi2rx.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index 77e2413c345aa..913f84c341f4b 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -40,6 +40,7 @@ #define CSI2RX_STREAM_BASE(n) (((n) + 1) * 0x100) #define CSI2RX_STREAM_CTRL_REG(n) (CSI2RX_STREAM_BASE(n) + 0x000) +#define CSI2RX_STREAM_CTRL_SOFT_RST BIT(4) #define CSI2RX_STREAM_CTRL_START BIT(0) #define CSI2RX_STREAM_DATA_CFG_REG(n) (CSI2RX_STREAM_BASE(n) + 0x008) @@ -134,12 +135,23 @@ struct csi2rx_priv *v4l2_subdev_to_csi2rx(struct v4l2_subdev *subdev) static void csi2rx_reset(struct csi2rx_priv *csi2rx) { + unsigned int i; + + /* Reset module */ writel(CSI2RX_SOFT_RESET_PROTOCOL | CSI2RX_SOFT_RESET_FRONT, csi2rx->base + CSI2RX_SOFT_RESET_REG); + /* Reset individual streams. */ + for (i = 0; i < csi2rx->max_streams; i++) { + writel(CSI2RX_STREAM_CTRL_SOFT_RST, + csi2rx->base + CSI2RX_STREAM_CTRL_REG(i)); + } - udelay(10); + usleep_range(10, 20); + /* Clear resets */ writel(0, csi2rx->base + CSI2RX_SOFT_RESET_REG); + for (i = 0; i < csi2rx->max_streams; i++) + writel(0, csi2rx->base + CSI2RX_STREAM_CTRL_REG(i)); } static int csi2rx_configure_ext_dphy(struct csi2rx_priv *csi2rx) -- GitLab From a64175fabfbdfe32e33024c5c5ecaf6646125fd6 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Mon, 9 Oct 2023 18:39:34 +0530 Subject: [PATCH 0534/1451] media: cadence: csi2rx: Set the STOP bit when stopping a stream The stream stop procedure says that the STOP bit should be set when the stream is to be stopped, and then the ready bit in stream status register polled to make sure the STOP operation is finished. Signed-off-by: Pratyush Yadav Tested-by: Julien Massot Reviewed-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Reviewed-by: Maxime Ripard Signed-off-by: Jai Luthra Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/platform/cadence/cdns-csi2rx.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index 913f84c341f4b..230c627ef1f48 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -41,8 +42,12 @@ #define CSI2RX_STREAM_CTRL_REG(n) (CSI2RX_STREAM_BASE(n) + 0x000) #define CSI2RX_STREAM_CTRL_SOFT_RST BIT(4) +#define CSI2RX_STREAM_CTRL_STOP BIT(1) #define CSI2RX_STREAM_CTRL_START BIT(0) +#define CSI2RX_STREAM_STATUS_REG(n) (CSI2RX_STREAM_BASE(n) + 0x004) +#define CSI2RX_STREAM_STATUS_RDY BIT(31) + #define CSI2RX_STREAM_DATA_CFG_REG(n) (CSI2RX_STREAM_BASE(n) + 0x008) #define CSI2RX_STREAM_DATA_CFG_EN_VC_SELECT BIT(31) #define CSI2RX_STREAM_DATA_CFG_VC_SELECT(n) BIT((n) + 16) @@ -310,13 +315,25 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) static void csi2rx_stop(struct csi2rx_priv *csi2rx) { unsigned int i; + u32 val; + int ret; clk_prepare_enable(csi2rx->p_clk); reset_control_assert(csi2rx->sys_rst); clk_disable_unprepare(csi2rx->sys_clk); for (i = 0; i < csi2rx->max_streams; i++) { - writel(0, csi2rx->base + CSI2RX_STREAM_CTRL_REG(i)); + writel(CSI2RX_STREAM_CTRL_STOP, + csi2rx->base + CSI2RX_STREAM_CTRL_REG(i)); + + ret = readl_relaxed_poll_timeout(csi2rx->base + + CSI2RX_STREAM_STATUS_REG(i), + val, + !(val & CSI2RX_STREAM_STATUS_RDY), + 10, 10000); + if (ret) + dev_warn(csi2rx->dev, + "Failed to stop streaming on pad%u\n", i); reset_control_assert(csi2rx->pixel_rst[i]); clk_disable_unprepare(csi2rx->pixel_clk[i]); -- GitLab From 1dd592748a80417ffc0f64eefe75a4e567d67f03 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Mon, 9 Oct 2023 18:39:35 +0530 Subject: [PATCH 0535/1451] media: cadence: csi2rx: Fix stream data configuration Firstly, there is no VC_EN bit present in the STREAM_DATA_CFG register. Bit 31 is part of the VL_SELECT field. Remove it completely. Secondly, it makes little sense to enable ith virtual channel for ith stream. Sure, there might be a use-case that demands it. But there might also be a use case that demands all streams to use the 0th virtual channel. Prefer this case over the former because it is less arbitrary and also makes it very clear what the limitations of the current driver is instead of giving a false impression that multiple virtual channels are supported. Signed-off-by: Pratyush Yadav Tested-by: Julien Massot Reviewed-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Reviewed-by: Maxime Ripard Signed-off-by: Jai Luthra Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/platform/cadence/cdns-csi2rx.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index 230c627ef1f48..812f31dfaab14 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -49,7 +49,6 @@ #define CSI2RX_STREAM_STATUS_RDY BIT(31) #define CSI2RX_STREAM_DATA_CFG_REG(n) (CSI2RX_STREAM_BASE(n) + 0x008) -#define CSI2RX_STREAM_DATA_CFG_EN_VC_SELECT BIT(31) #define CSI2RX_STREAM_DATA_CFG_VC_SELECT(n) BIT((n) + 16) #define CSI2RX_STREAM_CFG_REG(n) (CSI2RX_STREAM_BASE(n) + 0x00c) @@ -271,8 +270,11 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) writel(CSI2RX_STREAM_CFG_FIFO_MODE_LARGE_BUF, csi2rx->base + CSI2RX_STREAM_CFG_REG(i)); - writel(CSI2RX_STREAM_DATA_CFG_EN_VC_SELECT | - CSI2RX_STREAM_DATA_CFG_VC_SELECT(i), + /* + * Enable one virtual channel. When multiple virtual channels + * are supported this will have to be changed. + */ + writel(CSI2RX_STREAM_DATA_CFG_VC_SELECT(0), csi2rx->base + CSI2RX_STREAM_DATA_CFG_REG(i)); writel(CSI2RX_STREAM_CTRL_START, -- GitLab From c6ed7a39f177ef56f12a3427817566d2bbabcf03 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Mon, 9 Oct 2023 18:39:36 +0530 Subject: [PATCH 0536/1451] media: cadence: csi2rx: Populate subdev devnode The devnode can be used by media-ctl and other userspace tools to perform configurations on the subdev. Without it, media-ctl returns ENOENT when setting format on the sensor subdev. Signed-off-by: Pratyush Yadav Tested-by: Julien Massot Reviewed-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Reviewed-by: Maxime Ripard Signed-off-by: Jai Luthra Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/platform/cadence/cdns-csi2rx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index 812f31dfaab14..d0c2a5b3d0d57 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -668,6 +668,7 @@ static int csi2rx_probe(struct platform_device *pdev) csi2rx->pads[CSI2RX_PAD_SINK].flags = MEDIA_PAD_FL_SINK; for (i = CSI2RX_PAD_SOURCE_STREAM0; i < CSI2RX_PAD_MAX; i++) csi2rx->pads[i].flags = MEDIA_PAD_FL_SOURCE; + csi2rx->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ret = media_entity_pads_init(&csi2rx->subdev.entity, CSI2RX_PAD_MAX, csi2rx->pads); -- GitLab From b0f46ad6ed4af5eca481fad18825baafa0453a49 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Mon, 9 Oct 2023 18:39:37 +0530 Subject: [PATCH 0537/1451] media: cadence: csi2rx: Add link validation Add media link validation to make sure incorrectly configured pipelines are caught. Signed-off-by: Pratyush Yadav Tested-by: Julien Massot Reviewed-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Reviewed-by: Maxime Ripard Signed-off-by: Jai Luthra Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/platform/cadence/cdns-csi2rx.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index d0c2a5b3d0d57..889f4fbbafb3c 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -453,6 +453,10 @@ static const struct v4l2_subdev_ops csi2rx_subdev_ops = { .pad = &csi2rx_pad_ops, }; +static const struct media_entity_operations csi2rx_media_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + static int csi2rx_async_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *s_subdev, struct v4l2_async_connection *asd) @@ -669,6 +673,7 @@ static int csi2rx_probe(struct platform_device *pdev) for (i = CSI2RX_PAD_SOURCE_STREAM0; i < CSI2RX_PAD_MAX; i++) csi2rx->pads[i].flags = MEDIA_PAD_FL_SOURCE; csi2rx->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + csi2rx->subdev.entity.ops = &csi2rx_media_ops; ret = media_entity_pads_init(&csi2rx->subdev.entity, CSI2RX_PAD_MAX, csi2rx->pads); -- GitLab From ca5b901c1896c5232fb3dd637279980670e8e6b9 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Mon, 9 Oct 2023 18:39:38 +0530 Subject: [PATCH 0538/1451] media: dt-bindings: Add TI J721E CSI2RX TI's J721E uses the Cadence CSI2RX and DPHY peripherals to facilitate capture over a CSI-2 bus. The TI CSI2RX platform driver glues all the parts together. Signed-off-by: Pratyush Yadav Tested-by: Julien Massot Reviewed-by: Laurent Pinchart Reviewed-by: Rob Herring Signed-off-by: Jai Luthra Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../bindings/media/ti,j721e-csi2rx-shim.yaml | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/ti,j721e-csi2rx-shim.yaml diff --git a/Documentation/devicetree/bindings/media/ti,j721e-csi2rx-shim.yaml b/Documentation/devicetree/bindings/media/ti,j721e-csi2rx-shim.yaml new file mode 100644 index 0000000000000..f762fdc05e4d1 --- /dev/null +++ b/Documentation/devicetree/bindings/media/ti,j721e-csi2rx-shim.yaml @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/ti,j721e-csi2rx-shim.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI J721E CSI2RX Shim + +description: | + The TI J721E CSI2RX Shim is a wrapper around Cadence CSI2RX bridge that + enables sending captured frames to memory over PSI-L DMA. In the J721E + Technical Reference Manual (SPRUIL1B) it is referred to as "SHIM" under the + CSI_RX_IF section. + +maintainers: + - Jai Luthra + +properties: + compatible: + const: ti,j721e-csi2rx-shim + + dmas: + maxItems: 1 + + dma-names: + items: + - const: rx0 + + reg: + maxItems: 1 + + power-domains: + maxItems: 1 + + ranges: true + + "#address-cells": true + + "#size-cells": true + +patternProperties: + "^csi-bridge@": + type: object + description: CSI2 bridge node. + $ref: cdns,csi2rx.yaml# + +required: + - compatible + - reg + - dmas + - dma-names + - power-domains + - ranges + - "#address-cells" + - "#size-cells" + +additionalProperties: false + +examples: + - | + #include + + ti_csi2rx0: ticsi2rx@4500000 { + compatible = "ti,j721e-csi2rx-shim"; + dmas = <&main_udmap 0x4940>; + dma-names = "rx0"; + reg = <0x4500000 0x1000>; + power-domains = <&k3_pds 26 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + cdns_csi2rx: csi-bridge@4504000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x4504000 0x1000>; + clocks = <&k3_clks 26 2>, <&k3_clks 26 0>, <&k3_clks 26 2>, + <&k3_clks 26 2>, <&k3_clks 26 3>, <&k3_clks 26 3>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy0>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi2_0: port@0 { + + reg = <0>; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; + }; -- GitLab From b4a3d877dc92963a4db16ddb71df3d333c0d40bd Mon Sep 17 00:00:00 2001 From: Jai Luthra Date: Mon, 9 Oct 2023 18:39:39 +0530 Subject: [PATCH 0539/1451] media: ti: Add CSI2RX support for J721E TI's J721E uses the Cadence CSI2RX and DPHY peripherals to facilitate capture over a CSI-2 bus. The Cadence CSI2RX IP acts as a bridge between the TI specific parts and the CSI-2 protocol parts. TI then has a wrapper on top of this bridge called the SHIM layer. It takes in data from stream 0, repacks it, and sends it to memory over PSI-L DMA. This driver acts as the "front end" to V4L2 client applications. It implements the required ioctls and buffer operations, passes the necessary calls on to the bridge, programs the SHIM layer, and performs DMA via the dmaengine API to finally return the data to a buffer supplied by the application. Co-developed-by: Pratyush Yadav Signed-off-by: Pratyush Yadav Co-developed-by: Vaishnav Achath Signed-off-by: Vaishnav Achath Tested-by: Vaishnav Achath Tested-by: Julien Massot Reviewed-by: Tomi Valkeinen Signed-off-by: Jai Luthra Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- MAINTAINERS | 7 + drivers/media/platform/ti/Kconfig | 12 + drivers/media/platform/ti/Makefile | 1 + .../media/platform/ti/j721e-csi2rx/Makefile | 2 + .../platform/ti/j721e-csi2rx/j721e-csi2rx.c | 1159 +++++++++++++++++ 5 files changed, 1181 insertions(+) create mode 100644 drivers/media/platform/ti/j721e-csi2rx/Makefile create mode 100644 drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c diff --git a/MAINTAINERS b/MAINTAINERS index 83a0c7f3826b9..65cc6a982de95 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21594,6 +21594,13 @@ F: Documentation/devicetree/bindings/media/i2c/ti,ds90* F: drivers/media/i2c/ds90* F: include/media/i2c/ds90* +TI J721E CSI2RX DRIVER +M: Jai Luthra +L: linux-media@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/media/ti,j721e-csi2rx.yaml +F: drivers/media/platform/ti/j721e-csi2rx/ + TI KEYSTONE MULTICORE NAVIGATOR DRIVERS M: Nishanth Menon M: Santosh Shilimkar diff --git a/drivers/media/platform/ti/Kconfig b/drivers/media/platform/ti/Kconfig index e1ab56c3be1fe..bab998c4179ac 100644 --- a/drivers/media/platform/ti/Kconfig +++ b/drivers/media/platform/ti/Kconfig @@ -63,6 +63,18 @@ config VIDEO_TI_VPE_DEBUG help Enable debug messages on VPE driver. +config VIDEO_TI_J721E_CSI2RX + tristate "TI J721E CSI2RX wrapper layer driver" + depends on VIDEO_DEV && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_SUPPORT && MEDIA_CONTROLLER + depends on (PHY_CADENCE_DPHY_RX && VIDEO_CADENCE_CSI2RX) || COMPILE_TEST + depends on ARCH_K3 || COMPILE_TEST + select VIDEOBUF2_DMA_CONTIG + select V4L2_FWNODE + help + Support for TI CSI2RX wrapper layer. This just enables the wrapper driver. + The Cadence CSI2RX bridge driver needs to be enabled separately. + source "drivers/media/platform/ti/am437x/Kconfig" source "drivers/media/platform/ti/davinci/Kconfig" source "drivers/media/platform/ti/omap/Kconfig" diff --git a/drivers/media/platform/ti/Makefile b/drivers/media/platform/ti/Makefile index 98c5fe5c40d65..8a2f74c9380ea 100644 --- a/drivers/media/platform/ti/Makefile +++ b/drivers/media/platform/ti/Makefile @@ -3,5 +3,6 @@ obj-y += am437x/ obj-y += cal/ obj-y += vpe/ obj-y += davinci/ +obj-y += j721e-csi2rx/ obj-y += omap/ obj-y += omap3isp/ diff --git a/drivers/media/platform/ti/j721e-csi2rx/Makefile b/drivers/media/platform/ti/j721e-csi2rx/Makefile new file mode 100644 index 0000000000000..377afc1d62807 --- /dev/null +++ b/drivers/media/platform/ti/j721e-csi2rx/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_VIDEO_TI_J721E_CSI2RX) += j721e-csi2rx.o diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c new file mode 100644 index 0000000000000..ada61391c8d2f --- /dev/null +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -0,0 +1,1159 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * TI CSI2RX Shim Wrapper Driver + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + * Author: Pratyush Yadav + * Author: Jai Luthra + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define TI_CSI2RX_MODULE_NAME "j721e-csi2rx" + +#define SHIM_CNTL 0x10 +#define SHIM_CNTL_PIX_RST BIT(0) + +#define SHIM_DMACNTX 0x20 +#define SHIM_DMACNTX_EN BIT(31) +#define SHIM_DMACNTX_YUV422 GENMASK(27, 26) +#define SHIM_DMACNTX_SIZE GENMASK(21, 20) +#define SHIM_DMACNTX_FMT GENMASK(5, 0) +#define SHIM_DMACNTX_YUV422_MODE_11 3 +#define SHIM_DMACNTX_SIZE_8 0 +#define SHIM_DMACNTX_SIZE_16 1 +#define SHIM_DMACNTX_SIZE_32 2 + +#define SHIM_PSI_CFG0 0x24 +#define SHIM_PSI_CFG0_SRC_TAG GENMASK(15, 0) +#define SHIM_PSI_CFG0_DST_TAG GENMASK(31, 16) + +#define PSIL_WORD_SIZE_BYTES 16 +/* + * There are no hard limits on the width or height. The DMA engine can handle + * all sizes. The max width and height are arbitrary numbers for this driver. + * Use 16K * 16K as the arbitrary limit. It is large enough that it is unlikely + * the limit will be hit in practice. + */ +#define MAX_WIDTH_BYTES SZ_16K +#define MAX_HEIGHT_LINES SZ_16K + +#define DRAIN_TIMEOUT_MS 50 +#define DRAIN_BUFFER_SIZE SZ_32K + +struct ti_csi2rx_fmt { + u32 fourcc; /* Four character code. */ + u32 code; /* Mbus code. */ + u32 csi_dt; /* CSI Data type. */ + u8 bpp; /* Bits per pixel. */ + u8 size; /* Data size shift when unpacking. */ +}; + +struct ti_csi2rx_buffer { + /* Common v4l2 buffer. Must be first. */ + struct vb2_v4l2_buffer vb; + struct list_head list; + struct ti_csi2rx_dev *csi; +}; + +enum ti_csi2rx_dma_state { + TI_CSI2RX_DMA_STOPPED, /* Streaming not started yet. */ + TI_CSI2RX_DMA_IDLE, /* Streaming but no pending DMA operation. */ + TI_CSI2RX_DMA_ACTIVE, /* Streaming and pending DMA operation. */ +}; + +struct ti_csi2rx_dma { + /* Protects all fields in this struct. */ + spinlock_t lock; + struct dma_chan *chan; + /* Buffers queued to the driver, waiting to be processed by DMA. */ + struct list_head queue; + enum ti_csi2rx_dma_state state; + /* + * Queue of buffers submitted to DMA engine. + */ + struct list_head submitted; + /* Buffer to drain stale data from PSI-L endpoint */ + struct { + void *vaddr; + dma_addr_t paddr; + size_t len; + } drain; +}; + +struct ti_csi2rx_dev { + struct device *dev; + void __iomem *shim; + struct v4l2_device v4l2_dev; + struct video_device vdev; + struct media_device mdev; + struct media_pipeline pipe; + struct media_pad pad; + struct v4l2_async_notifier notifier; + struct v4l2_subdev *source; + struct vb2_queue vidq; + struct mutex mutex; /* To serialize ioctls. */ + struct v4l2_format v_fmt; + struct ti_csi2rx_dma dma; + u32 sequence; +}; + +static const struct ti_csi2rx_fmt ti_csi2rx_formats[] = { + { + .fourcc = V4L2_PIX_FMT_YUYV, + .code = MEDIA_BUS_FMT_YUYV8_1X16, + .csi_dt = MIPI_CSI2_DT_YUV422_8B, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_UYVY, + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .csi_dt = MIPI_CSI2_DT_YUV422_8B, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_YVYU, + .code = MEDIA_BUS_FMT_YVYU8_1X16, + .csi_dt = MIPI_CSI2_DT_YUV422_8B, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_VYUY, + .code = MEDIA_BUS_FMT_VYUY8_1X16, + .csi_dt = MIPI_CSI2_DT_YUV422_8B, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .bpp = 8, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .bpp = 8, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .bpp = 8, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .bpp = 8, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .code = MEDIA_BUS_FMT_SGBRG10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, + + /* More formats can be supported but they are not listed for now. */ +}; + +/* Forward declaration needed by ti_csi2rx_dma_callback. */ +static int ti_csi2rx_start_dma(struct ti_csi2rx_dev *csi, + struct ti_csi2rx_buffer *buf); + +static const struct ti_csi2rx_fmt *find_format_by_fourcc(u32 pixelformat) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ti_csi2rx_formats); i++) { + if (ti_csi2rx_formats[i].fourcc == pixelformat) + return &ti_csi2rx_formats[i]; + } + + return NULL; +} + +static const struct ti_csi2rx_fmt *find_format_by_code(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ti_csi2rx_formats); i++) { + if (ti_csi2rx_formats[i].code == code) + return &ti_csi2rx_formats[i]; + } + + return NULL; +} + +static void ti_csi2rx_fill_fmt(const struct ti_csi2rx_fmt *csi_fmt, + struct v4l2_format *v4l2_fmt) +{ + struct v4l2_pix_format *pix = &v4l2_fmt->fmt.pix; + unsigned int pixels_in_word; + + pixels_in_word = PSIL_WORD_SIZE_BYTES * 8 / csi_fmt->bpp; + + /* Clamp width and height to sensible maximums (16K x 16K) */ + pix->width = clamp_t(unsigned int, pix->width, + pixels_in_word, + MAX_WIDTH_BYTES * 8 / csi_fmt->bpp); + pix->height = clamp_t(unsigned int, pix->height, 1, MAX_HEIGHT_LINES); + + /* Width should be a multiple of transfer word-size */ + pix->width = rounddown(pix->width, pixels_in_word); + + v4l2_fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + pix->pixelformat = csi_fmt->fourcc; + pix->bytesperline = pix->width * (csi_fmt->bpp / 8); + pix->sizeimage = pix->bytesperline * pix->height; +} + +static int ti_csi2rx_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, TI_CSI2RX_MODULE_NAME, sizeof(cap->driver)); + strscpy(cap->card, TI_CSI2RX_MODULE_NAME, sizeof(cap->card)); + + return 0; +} + +static int ti_csi2rx_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + const struct ti_csi2rx_fmt *fmt = NULL; + + if (f->mbus_code) { + /* 1-to-1 mapping between bus formats and pixel formats */ + if (f->index > 0) + return -EINVAL; + + fmt = find_format_by_code(f->mbus_code); + } else { + if (f->index >= ARRAY_SIZE(ti_csi2rx_formats)) + return -EINVAL; + + fmt = &ti_csi2rx_formats[f->index]; + } + + if (!fmt) + return -EINVAL; + + f->pixelformat = fmt->fourcc; + memset(f->reserved, 0, sizeof(f->reserved)); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + return 0; +} + +static int ti_csi2rx_g_fmt_vid_cap(struct file *file, void *prov, + struct v4l2_format *f) +{ + struct ti_csi2rx_dev *csi = video_drvdata(file); + + *f = csi->v_fmt; + + return 0; +} + +static int ti_csi2rx_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + const struct ti_csi2rx_fmt *fmt; + + /* + * Default to the first format if the requested pixel format code isn't + * supported. + */ + fmt = find_format_by_fourcc(f->fmt.pix.pixelformat); + if (!fmt) + fmt = &ti_csi2rx_formats[0]; + + /* Interlaced formats are not supported. */ + f->fmt.pix.field = V4L2_FIELD_NONE; + + ti_csi2rx_fill_fmt(fmt, f); + + return 0; +} + +static int ti_csi2rx_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct ti_csi2rx_dev *csi = video_drvdata(file); + struct vb2_queue *q = &csi->vidq; + int ret; + + if (vb2_is_busy(q)) + return -EBUSY; + + ret = ti_csi2rx_try_fmt_vid_cap(file, priv, f); + if (ret < 0) + return ret; + + csi->v_fmt = *f; + + return 0; +} + +static int ti_csi2rx_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + const struct ti_csi2rx_fmt *fmt; + unsigned int pixels_in_word; + + fmt = find_format_by_fourcc(fsize->pixel_format); + if (!fmt || fsize->index != 0) + return -EINVAL; + + /* + * Number of pixels in one PSI-L word. The transfer happens in multiples + * of PSI-L word sizes. + */ + pixels_in_word = PSIL_WORD_SIZE_BYTES * 8 / fmt->bpp; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = pixels_in_word; + fsize->stepwise.max_width = rounddown(MAX_WIDTH_BYTES * 8 / fmt->bpp, + pixels_in_word); + fsize->stepwise.step_width = pixels_in_word; + fsize->stepwise.min_height = 1; + fsize->stepwise.max_height = MAX_HEIGHT_LINES; + fsize->stepwise.step_height = 1; + + return 0; +} + +static const struct v4l2_ioctl_ops csi_ioctl_ops = { + .vidioc_querycap = ti_csi2rx_querycap, + .vidioc_enum_fmt_vid_cap = ti_csi2rx_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = ti_csi2rx_try_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = ti_csi2rx_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = ti_csi2rx_s_fmt_vid_cap, + .vidioc_enum_framesizes = ti_csi2rx_enum_framesizes, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +static const struct v4l2_file_operations csi_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, +}; + +static int csi_async_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_connection *asc) +{ + struct ti_csi2rx_dev *csi = dev_get_drvdata(notifier->v4l2_dev->dev); + + csi->source = subdev; + + return 0; +} + +static int csi_async_notifier_complete(struct v4l2_async_notifier *notifier) +{ + struct ti_csi2rx_dev *csi = dev_get_drvdata(notifier->v4l2_dev->dev); + struct video_device *vdev = &csi->vdev; + int ret; + + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) + return ret; + + ret = v4l2_create_fwnode_links_to_pad(csi->source, &csi->pad, + MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); + + if (ret) { + video_unregister_device(vdev); + return ret; + } + + ret = v4l2_device_register_subdev_nodes(&csi->v4l2_dev); + if (ret) + video_unregister_device(vdev); + + return ret; +} + +static const struct v4l2_async_notifier_operations csi_async_notifier_ops = { + .bound = csi_async_notifier_bound, + .complete = csi_async_notifier_complete, +}; + +static int ti_csi2rx_notifier_register(struct ti_csi2rx_dev *csi) +{ + struct fwnode_handle *fwnode; + struct v4l2_async_connection *asc; + struct device_node *node; + int ret; + + node = of_get_child_by_name(csi->dev->of_node, "csi-bridge"); + if (!node) + return -EINVAL; + + fwnode = of_fwnode_handle(node); + if (!fwnode) { + of_node_put(node); + return -EINVAL; + } + + v4l2_async_nf_init(&csi->notifier, &csi->v4l2_dev); + csi->notifier.ops = &csi_async_notifier_ops; + + asc = v4l2_async_nf_add_fwnode(&csi->notifier, fwnode, + struct v4l2_async_connection); + of_node_put(node); + if (IS_ERR(asc)) { + v4l2_async_nf_cleanup(&csi->notifier); + return PTR_ERR(asc); + } + + ret = v4l2_async_nf_register(&csi->notifier); + if (ret) { + v4l2_async_nf_cleanup(&csi->notifier); + return ret; + } + + return 0; +} + +static void ti_csi2rx_setup_shim(struct ti_csi2rx_dev *csi) +{ + const struct ti_csi2rx_fmt *fmt; + unsigned int reg; + + fmt = find_format_by_fourcc(csi->v_fmt.fmt.pix.pixelformat); + + /* De-assert the pixel interface reset. */ + reg = SHIM_CNTL_PIX_RST; + writel(reg, csi->shim + SHIM_CNTL); + + reg = SHIM_DMACNTX_EN; + reg |= FIELD_PREP(SHIM_DMACNTX_FMT, fmt->csi_dt); + + /* + * The hardware assumes incoming YUV422 8-bit data on MIPI CSI2 bus + * follows the spec and is packed in the order U0 -> Y0 -> V0 -> Y1 -> + * ... + * + * There is an option to swap the bytes around before storing in + * memory, to achieve different pixel formats: + * + * Byte3 <----------- Byte0 + * [ Y1 ][ V0 ][ Y0 ][ U0 ] MODE 11 + * [ Y1 ][ U0 ][ Y0 ][ V0 ] MODE 10 + * [ V0 ][ Y1 ][ U0 ][ Y0 ] MODE 01 + * [ U0 ][ Y1 ][ V0 ][ Y0 ] MODE 00 + * + * We don't have any requirement to change pixelformat from what is + * coming from the source, so we keep it in MODE 11, which does not + * swap any bytes when storing in memory. + */ + switch (fmt->fourcc) { + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + reg |= FIELD_PREP(SHIM_DMACNTX_YUV422, + SHIM_DMACNTX_YUV422_MODE_11); + break; + default: + /* Ignore if not YUV 4:2:2 */ + break; + } + + reg |= FIELD_PREP(SHIM_DMACNTX_SIZE, fmt->size); + + writel(reg, csi->shim + SHIM_DMACNTX); + + reg = FIELD_PREP(SHIM_PSI_CFG0_SRC_TAG, 0) | + FIELD_PREP(SHIM_PSI_CFG0_DST_TAG, 0); + writel(reg, csi->shim + SHIM_PSI_CFG0); +} + +static void ti_csi2rx_drain_callback(void *param) +{ + struct completion *drain_complete = param; + + complete(drain_complete); +} + +/* + * Drain the stale data left at the PSI-L endpoint. + * + * This might happen if no buffers are queued in time but source is still + * streaming. In multi-stream scenarios this can happen when one stream is + * stopped but other is still streaming, and thus module-level pixel reset is + * not asserted. + * + * To prevent that stale data corrupting the subsequent transactions, it is + * required to issue DMA requests to drain it out. + */ +static int ti_csi2rx_drain_dma(struct ti_csi2rx_dev *csi) +{ + struct dma_async_tx_descriptor *desc; + struct completion drain_complete; + dma_cookie_t cookie; + int ret; + + init_completion(&drain_complete); + + desc = dmaengine_prep_slave_single(csi->dma.chan, csi->dma.drain.paddr, + csi->dma.drain.len, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + ret = -EIO; + goto out; + } + + desc->callback = ti_csi2rx_drain_callback; + desc->callback_param = &drain_complete; + + cookie = dmaengine_submit(desc); + ret = dma_submit_error(cookie); + if (ret) + goto out; + + dma_async_issue_pending(csi->dma.chan); + + if (!wait_for_completion_timeout(&drain_complete, + msecs_to_jiffies(DRAIN_TIMEOUT_MS))) { + dmaengine_terminate_sync(csi->dma.chan); + dev_dbg(csi->dev, "DMA transfer timed out for drain buffer\n"); + ret = -ETIMEDOUT; + goto out; + } +out: + return ret; +} + +static void ti_csi2rx_dma_callback(void *param) +{ + struct ti_csi2rx_buffer *buf = param; + struct ti_csi2rx_dev *csi = buf->csi; + struct ti_csi2rx_dma *dma = &csi->dma; + unsigned long flags; + + /* + * TODO: Derive the sequence number from the CSI2RX frame number + * hardware monitor registers. + */ + buf->vb.vb2_buf.timestamp = ktime_get_ns(); + buf->vb.sequence = csi->sequence++; + + spin_lock_irqsave(&dma->lock, flags); + + WARN_ON(!list_is_first(&buf->list, &dma->submitted)); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + list_del(&buf->list); + + /* If there are more buffers to process then start their transfer. */ + while (!list_empty(&dma->queue)) { + buf = list_entry(dma->queue.next, struct ti_csi2rx_buffer, list); + + if (ti_csi2rx_start_dma(csi, buf)) { + dev_err(csi->dev, "Failed to queue the next buffer for DMA\n"); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } else { + list_move_tail(&buf->list, &dma->submitted); + } + } + + if (list_empty(&dma->submitted)) + dma->state = TI_CSI2RX_DMA_IDLE; + + spin_unlock_irqrestore(&dma->lock, flags); +} + +static int ti_csi2rx_start_dma(struct ti_csi2rx_dev *csi, + struct ti_csi2rx_buffer *buf) +{ + unsigned long addr; + struct dma_async_tx_descriptor *desc; + size_t len = csi->v_fmt.fmt.pix.sizeimage; + dma_cookie_t cookie; + int ret = 0; + + addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); + desc = dmaengine_prep_slave_single(csi->dma.chan, addr, len, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) + return -EIO; + + desc->callback = ti_csi2rx_dma_callback; + desc->callback_param = buf; + + cookie = dmaengine_submit(desc); + ret = dma_submit_error(cookie); + if (ret) + return ret; + + dma_async_issue_pending(csi->dma.chan); + + return 0; +} + +static void ti_csi2rx_stop_dma(struct ti_csi2rx_dev *csi) +{ + struct ti_csi2rx_dma *dma = &csi->dma; + enum ti_csi2rx_dma_state state; + unsigned long flags; + int ret; + + spin_lock_irqsave(&dma->lock, flags); + state = csi->dma.state; + dma->state = TI_CSI2RX_DMA_STOPPED; + spin_unlock_irqrestore(&dma->lock, flags); + + if (state != TI_CSI2RX_DMA_STOPPED) { + /* + * Normal DMA termination does not clean up pending data on + * the endpoint if multiple streams are running and only one + * is stopped, as the module-level pixel reset cannot be + * enforced before terminating DMA. + */ + ret = ti_csi2rx_drain_dma(csi); + if (ret && ret != -ETIMEDOUT) + dev_warn(csi->dev, + "Failed to drain DMA. Next frame might be bogus\n"); + } + + ret = dmaengine_terminate_sync(csi->dma.chan); + if (ret) + dev_err(csi->dev, "Failed to stop DMA: %d\n", ret); +} + +static void ti_csi2rx_cleanup_buffers(struct ti_csi2rx_dev *csi, + enum vb2_buffer_state state) +{ + struct ti_csi2rx_dma *dma = &csi->dma; + struct ti_csi2rx_buffer *buf, *tmp; + unsigned long flags; + + spin_lock_irqsave(&dma->lock, flags); + list_for_each_entry_safe(buf, tmp, &csi->dma.queue, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, state); + } + list_for_each_entry_safe(buf, tmp, &csi->dma.submitted, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, state); + } + spin_unlock_irqrestore(&dma->lock, flags); +} + +static int ti_csi2rx_queue_setup(struct vb2_queue *q, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct ti_csi2rx_dev *csi = vb2_get_drv_priv(q); + unsigned int size = csi->v_fmt.fmt.pix.sizeimage; + + if (*nplanes) { + if (sizes[0] < size) + return -EINVAL; + size = sizes[0]; + } + + *nplanes = 1; + sizes[0] = size; + + return 0; +} + +static int ti_csi2rx_buffer_prepare(struct vb2_buffer *vb) +{ + struct ti_csi2rx_dev *csi = vb2_get_drv_priv(vb->vb2_queue); + unsigned long size = csi->v_fmt.fmt.pix.sizeimage; + + if (vb2_plane_size(vb, 0) < size) { + dev_err(csi->dev, "Data will not fit into plane\n"); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, size); + return 0; +} + +static void ti_csi2rx_buffer_queue(struct vb2_buffer *vb) +{ + struct ti_csi2rx_dev *csi = vb2_get_drv_priv(vb->vb2_queue); + struct ti_csi2rx_buffer *buf; + struct ti_csi2rx_dma *dma = &csi->dma; + bool restart_dma = false; + unsigned long flags = 0; + int ret; + + buf = container_of(vb, struct ti_csi2rx_buffer, vb.vb2_buf); + buf->csi = csi; + + spin_lock_irqsave(&dma->lock, flags); + /* + * Usually the DMA callback takes care of queueing the pending buffers. + * But if DMA has stalled due to lack of buffers, restart it now. + */ + if (dma->state == TI_CSI2RX_DMA_IDLE) { + /* + * Do not restart DMA with the lock held because + * ti_csi2rx_drain_dma() might block for completion. + * There won't be a race on queueing DMA anyway since the + * callback is not being fired. + */ + restart_dma = true; + dma->state = TI_CSI2RX_DMA_ACTIVE; + } else { + list_add_tail(&buf->list, &dma->queue); + } + spin_unlock_irqrestore(&dma->lock, flags); + + if (restart_dma) { + /* + * Once frames start dropping, some data gets stuck in the DMA + * pipeline somewhere. So the first DMA transfer after frame + * drops gives a partial frame. This is obviously not useful to + * the application and will only confuse it. Issue a DMA + * transaction to drain that up. + */ + ret = ti_csi2rx_drain_dma(csi); + if (ret && ret != -ETIMEDOUT) + dev_warn(csi->dev, + "Failed to drain DMA. Next frame might be bogus\n"); + + ret = ti_csi2rx_start_dma(csi, buf); + if (ret) { + dev_err(csi->dev, "Failed to start DMA: %d\n", ret); + spin_lock_irqsave(&dma->lock, flags); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + dma->state = TI_CSI2RX_DMA_IDLE; + spin_unlock_irqrestore(&dma->lock, flags); + } else { + spin_lock_irqsave(&dma->lock, flags); + list_add_tail(&buf->list, &dma->submitted); + spin_unlock_irqrestore(&dma->lock, flags); + } + } +} + +static int ti_csi2rx_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct ti_csi2rx_dev *csi = vb2_get_drv_priv(vq); + struct ti_csi2rx_dma *dma = &csi->dma; + struct ti_csi2rx_buffer *buf; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&dma->lock, flags); + if (list_empty(&dma->queue)) + ret = -EIO; + spin_unlock_irqrestore(&dma->lock, flags); + if (ret) + return ret; + + ret = video_device_pipeline_start(&csi->vdev, &csi->pipe); + if (ret) + goto err; + + ti_csi2rx_setup_shim(csi); + + csi->sequence = 0; + + spin_lock_irqsave(&dma->lock, flags); + buf = list_entry(dma->queue.next, struct ti_csi2rx_buffer, list); + + ret = ti_csi2rx_start_dma(csi, buf); + if (ret) { + dev_err(csi->dev, "Failed to start DMA: %d\n", ret); + spin_unlock_irqrestore(&dma->lock, flags); + goto err_pipeline; + } + + list_move_tail(&buf->list, &dma->submitted); + dma->state = TI_CSI2RX_DMA_ACTIVE; + spin_unlock_irqrestore(&dma->lock, flags); + + ret = v4l2_subdev_call(csi->source, video, s_stream, 1); + if (ret) + goto err_dma; + + return 0; + +err_dma: + ti_csi2rx_stop_dma(csi); +err_pipeline: + video_device_pipeline_stop(&csi->vdev); + writel(0, csi->shim + SHIM_CNTL); + writel(0, csi->shim + SHIM_DMACNTX); +err: + ti_csi2rx_cleanup_buffers(csi, VB2_BUF_STATE_QUEUED); + return ret; +} + +static void ti_csi2rx_stop_streaming(struct vb2_queue *vq) +{ + struct ti_csi2rx_dev *csi = vb2_get_drv_priv(vq); + int ret; + + video_device_pipeline_stop(&csi->vdev); + + writel(0, csi->shim + SHIM_CNTL); + writel(0, csi->shim + SHIM_DMACNTX); + + ret = v4l2_subdev_call(csi->source, video, s_stream, 0); + if (ret) + dev_err(csi->dev, "Failed to stop subdev stream\n"); + + ti_csi2rx_stop_dma(csi); + ti_csi2rx_cleanup_buffers(csi, VB2_BUF_STATE_ERROR); +} + +static const struct vb2_ops csi_vb2_qops = { + .queue_setup = ti_csi2rx_queue_setup, + .buf_prepare = ti_csi2rx_buffer_prepare, + .buf_queue = ti_csi2rx_buffer_queue, + .start_streaming = ti_csi2rx_start_streaming, + .stop_streaming = ti_csi2rx_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static int ti_csi2rx_init_vb2q(struct ti_csi2rx_dev *csi) +{ + struct vb2_queue *q = &csi->vidq; + int ret; + + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->drv_priv = csi; + q->buf_struct_size = sizeof(struct ti_csi2rx_buffer); + q->ops = &csi_vb2_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->dev = dmaengine_get_dma_device(csi->dma.chan); + q->lock = &csi->mutex; + q->min_buffers_needed = 1; + + ret = vb2_queue_init(q); + if (ret) + return ret; + + csi->vdev.queue = q; + + return 0; +} + +static int ti_csi2rx_link_validate(struct media_link *link) +{ + struct media_entity *entity = link->sink->entity; + struct video_device *vdev = media_entity_to_video_device(entity); + struct ti_csi2rx_dev *csi = container_of(vdev, struct ti_csi2rx_dev, vdev); + struct v4l2_pix_format *csi_fmt = &csi->v_fmt.fmt.pix; + struct v4l2_subdev_format source_fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .pad = link->source->index, + }; + const struct ti_csi2rx_fmt *ti_fmt; + int ret; + + ret = v4l2_subdev_call_state_active(csi->source, pad, + get_fmt, &source_fmt); + if (ret) + return ret; + + if (source_fmt.format.width != csi_fmt->width) { + dev_dbg(csi->dev, "Width does not match (source %u, sink %u)\n", + source_fmt.format.width, csi_fmt->width); + return -EPIPE; + } + + if (source_fmt.format.height != csi_fmt->height) { + dev_dbg(csi->dev, "Height does not match (source %u, sink %u)\n", + source_fmt.format.height, csi_fmt->height); + return -EPIPE; + } + + if (source_fmt.format.field != csi_fmt->field && + csi_fmt->field != V4L2_FIELD_NONE) { + dev_dbg(csi->dev, "Field does not match (source %u, sink %u)\n", + source_fmt.format.field, csi_fmt->field); + return -EPIPE; + } + + ti_fmt = find_format_by_code(source_fmt.format.code); + if (!ti_fmt) { + dev_dbg(csi->dev, "Media bus format 0x%x not supported\n", + source_fmt.format.code); + return -EPIPE; + } + + if (ti_fmt->fourcc != csi_fmt->pixelformat) { + dev_dbg(csi->dev, + "Cannot transform source fmt 0x%x to sink fmt 0x%x\n", + ti_fmt->fourcc, csi_fmt->pixelformat); + return -EPIPE; + } + + return 0; +} + +static const struct media_entity_operations ti_csi2rx_video_entity_ops = { + .link_validate = ti_csi2rx_link_validate, +}; + +static int ti_csi2rx_init_dma(struct ti_csi2rx_dev *csi) +{ + struct dma_slave_config cfg = { + .src_addr_width = DMA_SLAVE_BUSWIDTH_16_BYTES, + }; + int ret; + + INIT_LIST_HEAD(&csi->dma.queue); + INIT_LIST_HEAD(&csi->dma.submitted); + spin_lock_init(&csi->dma.lock); + + csi->dma.state = TI_CSI2RX_DMA_STOPPED; + + csi->dma.chan = dma_request_chan(csi->dev, "rx0"); + if (IS_ERR(csi->dma.chan)) + return PTR_ERR(csi->dma.chan); + + ret = dmaengine_slave_config(csi->dma.chan, &cfg); + if (ret) { + dma_release_channel(csi->dma.chan); + return ret; + } + + csi->dma.drain.len = DRAIN_BUFFER_SIZE; + csi->dma.drain.vaddr = dma_alloc_coherent(csi->dev, csi->dma.drain.len, + &csi->dma.drain.paddr, + GFP_KERNEL); + if (!csi->dma.drain.vaddr) + return -ENOMEM; + + return 0; +} + +static int ti_csi2rx_v4l2_init(struct ti_csi2rx_dev *csi) +{ + struct media_device *mdev = &csi->mdev; + struct video_device *vdev = &csi->vdev; + const struct ti_csi2rx_fmt *fmt; + struct v4l2_pix_format *pix_fmt = &csi->v_fmt.fmt.pix; + int ret; + + fmt = find_format_by_fourcc(V4L2_PIX_FMT_UYVY); + if (!fmt) + return -EINVAL; + + pix_fmt->width = 640; + pix_fmt->height = 480; + pix_fmt->field = V4L2_FIELD_NONE; + pix_fmt->colorspace = V4L2_COLORSPACE_SRGB; + pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601, + pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE, + pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB, + + ti_csi2rx_fill_fmt(fmt, &csi->v_fmt); + + mdev->dev = csi->dev; + mdev->hw_revision = 1; + strscpy(mdev->model, "TI-CSI2RX", sizeof(mdev->model)); + + media_device_init(mdev); + + strscpy(vdev->name, TI_CSI2RX_MODULE_NAME, sizeof(vdev->name)); + vdev->v4l2_dev = &csi->v4l2_dev; + vdev->vfl_dir = VFL_DIR_RX; + vdev->fops = &csi_fops; + vdev->ioctl_ops = &csi_ioctl_ops; + vdev->release = video_device_release_empty; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_IO_MC; + vdev->lock = &csi->mutex; + video_set_drvdata(vdev, csi); + + csi->pad.flags = MEDIA_PAD_FL_SINK; + vdev->entity.ops = &ti_csi2rx_video_entity_ops; + ret = media_entity_pads_init(&csi->vdev.entity, 1, &csi->pad); + if (ret) + return ret; + + csi->v4l2_dev.mdev = mdev; + + ret = v4l2_device_register(csi->dev, &csi->v4l2_dev); + if (ret) + return ret; + + ret = media_device_register(mdev); + if (ret) { + v4l2_device_unregister(&csi->v4l2_dev); + media_device_cleanup(mdev); + return ret; + } + + return 0; +} + +static void ti_csi2rx_cleanup_dma(struct ti_csi2rx_dev *csi) +{ + dma_free_coherent(csi->dev, csi->dma.drain.len, + csi->dma.drain.vaddr, csi->dma.drain.paddr); + csi->dma.drain.vaddr = NULL; + dma_release_channel(csi->dma.chan); +} + +static void ti_csi2rx_cleanup_v4l2(struct ti_csi2rx_dev *csi) +{ + media_device_unregister(&csi->mdev); + v4l2_device_unregister(&csi->v4l2_dev); + media_device_cleanup(&csi->mdev); +} + +static void ti_csi2rx_cleanup_subdev(struct ti_csi2rx_dev *csi) +{ + v4l2_async_nf_unregister(&csi->notifier); + v4l2_async_nf_cleanup(&csi->notifier); +} + +static void ti_csi2rx_cleanup_vb2q(struct ti_csi2rx_dev *csi) +{ + vb2_queue_release(&csi->vidq); +} + +static int ti_csi2rx_probe(struct platform_device *pdev) +{ + struct ti_csi2rx_dev *csi; + struct resource *res; + int ret; + + csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL); + if (!csi) + return -ENOMEM; + + csi->dev = &pdev->dev; + platform_set_drvdata(pdev, csi); + + mutex_init(&csi->mutex); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + csi->shim = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(csi->shim)) { + ret = PTR_ERR(csi->shim); + goto err_mutex; + } + + ret = ti_csi2rx_init_dma(csi); + if (ret) + goto err_mutex; + + ret = ti_csi2rx_v4l2_init(csi); + if (ret) + goto err_dma; + + ret = ti_csi2rx_init_vb2q(csi); + if (ret) + goto err_v4l2; + + ret = ti_csi2rx_notifier_register(csi); + if (ret) + goto err_vb2q; + + ret = of_platform_populate(csi->dev->of_node, NULL, NULL, csi->dev); + if (ret) { + dev_err(csi->dev, "Failed to create children: %d\n", ret); + goto err_subdev; + } + + return 0; + +err_subdev: + ti_csi2rx_cleanup_subdev(csi); +err_vb2q: + ti_csi2rx_cleanup_vb2q(csi); +err_v4l2: + ti_csi2rx_cleanup_v4l2(csi); +err_dma: + ti_csi2rx_cleanup_dma(csi); +err_mutex: + mutex_destroy(&csi->mutex); + return ret; +} + +static int ti_csi2rx_remove(struct platform_device *pdev) +{ + struct ti_csi2rx_dev *csi = platform_get_drvdata(pdev); + + video_unregister_device(&csi->vdev); + + ti_csi2rx_cleanup_vb2q(csi); + ti_csi2rx_cleanup_subdev(csi); + ti_csi2rx_cleanup_v4l2(csi); + ti_csi2rx_cleanup_dma(csi); + + mutex_destroy(&csi->mutex); + + return 0; +} + +static const struct of_device_id ti_csi2rx_of_match[] = { + { .compatible = "ti,j721e-csi2rx-shim", }, + { }, +}; +MODULE_DEVICE_TABLE(of, ti_csi2rx_of_match); + +static struct platform_driver ti_csi2rx_pdrv = { + .probe = ti_csi2rx_probe, + .remove = ti_csi2rx_remove, + .driver = { + .name = TI_CSI2RX_MODULE_NAME, + .of_match_table = ti_csi2rx_of_match, + }, +}; + +module_platform_driver(ti_csi2rx_pdrv); + +MODULE_DESCRIPTION("TI J721E CSI2 RX Driver"); +MODULE_AUTHOR("Jai Luthra "); +MODULE_LICENSE("GPL"); -- GitLab From 3b34d7fbb7272f6a34e1340c9563129d6235ced3 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 6 Oct 2023 14:40:56 +0200 Subject: [PATCH 0540/1451] media: dt-bindings: hynix,hi846: Add video-interface-devices properties Allow properties from video-interface-devices.yaml for the SK Hynix Hi-846 sensor. All properties specified in video-interface-devices.yaml schema are valid, so make them accepted by changing "additionalProperties: false" to "unevaluatedProperties: false" at the schema top-level. Add two properties from video-interface-devices.yaml to the example to validate the new schema. Signed-off-by: Jacopo Mondi Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../devicetree/bindings/media/i2c/hynix,hi846.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/media/i2c/hynix,hi846.yaml b/Documentation/devicetree/bindings/media/i2c/hynix,hi846.yaml index 1e2df8cf2937b..60f19e1152b33 100644 --- a/Documentation/devicetree/bindings/media/i2c/hynix,hi846.yaml +++ b/Documentation/devicetree/bindings/media/i2c/hynix,hi846.yaml @@ -14,6 +14,9 @@ description: |- interface and CCI (I2C compatible) control bus. The output format is raw Bayer. +allOf: + - $ref: /schemas/media/video-interface-devices.yaml# + properties: compatible: const: hynix,hi846 @@ -86,7 +89,7 @@ required: - vddd-supply - port -additionalProperties: false +unevaluatedProperties: false examples: - | @@ -109,6 +112,8 @@ examples: vddio-supply = <®_camera_vddio>; reset-gpios = <&gpio1 25 GPIO_ACTIVE_LOW>; shutdown-gpios = <&gpio5 4 GPIO_ACTIVE_LOW>; + orientation = <0>; + rotation = <0>; port { camera_out: endpoint { -- GitLab From d85ce91477779973cad8c57d652381e724afd671 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 6 Oct 2023 14:40:57 +0200 Subject: [PATCH 0541/1451] media: dt-bindings: ovti,ov02a10: Allow props from video-interface-devices There is no reason to restrict the allowed rotation degrees to 0 and 180, as the sensor can be mounted with any rotation. Also, as all the properties described by video-interface-devices.yaml are allowed for the image sensor, make them accepted by changing "additionalProperties: false" to "unevaluatedProperties: false" at the schema top-level. Signed-off-by: Jacopo Mondi Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../devicetree/bindings/media/i2c/ovti,ov02a10.yaml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov02a10.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov02a10.yaml index 763cebe03dc20..67c1c291327b7 100644 --- a/Documentation/devicetree/bindings/media/i2c/ovti,ov02a10.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov02a10.yaml @@ -68,12 +68,6 @@ properties: marked GPIO_ACTIVE_LOW. maxItems: 1 - rotation: - enum: - - 0 # Sensor Mounted Upright - - 180 # Sensor Mounted Upside Down - default: 0 - port: $ref: /schemas/graph.yaml#/$defs/port-base additionalProperties: false @@ -114,7 +108,7 @@ required: - reset-gpios - port -additionalProperties: false +unevaluatedProperties: false examples: - | -- GitLab From d16928772eec540b61e98f25c0dd7b57404070d1 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 6 Oct 2023 14:40:58 +0200 Subject: [PATCH 0542/1451] media: dt-bindings: ovti,ov4689: Allow props from video-interface-devices All the properties described by video-interface-devices.yaml are allowed for the image sensor, make them accepted by changing "additionalProperties: false" to "unevaluatedProperties: false" at the schema top-level. Signed-off-by: Jacopo Mondi Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../devicetree/bindings/media/i2c/ovti,ov4689.yaml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov4689.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov4689.yaml index 50579c947f3c2..d96199031b66c 100644 --- a/Documentation/devicetree/bindings/media/i2c/ovti,ov4689.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov4689.yaml @@ -52,10 +52,6 @@ properties: description: GPIO connected to the reset pin (active low) - orientation: true - - rotation: true - port: $ref: /schemas/graph.yaml#/$defs/port-base additionalProperties: false @@ -95,7 +91,7 @@ required: - dvdd-supply - port -additionalProperties: false +unevaluatedProperties: false examples: - | -- GitLab From d175296a2df34fc2acebc5511a5fac8c977bda15 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 6 Oct 2023 14:40:59 +0200 Subject: [PATCH 0543/1451] media: dt-bindings: ovti,ov5640: Allow props from video-interface-devices There is no reason to restrict the allowed rotation degrees to 0 and 180, as the sensor can be mounted with any rotation. Also, as all the properties described by video-interface-devices.yaml are allowed for the image sensor, make them accepted by changing "additionalProperties: false" to "unevaluatedProperties: false" at the schema top-level. Signed-off-by: Jacopo Mondi Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../devicetree/bindings/media/i2c/ovti,ov5640.yaml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov5640.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov5640.yaml index a621032f9bd07..2c5e69356658e 100644 --- a/Documentation/devicetree/bindings/media/i2c/ovti,ov5640.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov5640.yaml @@ -44,11 +44,6 @@ properties: description: > Reference to the GPIO connected to the reset pin, if any. - rotation: - enum: - - 0 - - 180 - port: description: Digital Output Port $ref: /schemas/graph.yaml#/$defs/port-base @@ -85,7 +80,7 @@ required: - DOVDD-supply - port -additionalProperties: false +unevaluatedProperties: false examples: - | -- GitLab From af91ed3587b84629d862b144bccfdf2295f8075a Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 6 Oct 2023 14:41:00 +0200 Subject: [PATCH 0544/1451] media: dt-bindings: sony,imx214: Allow props from video-interface-devices All the properties described by video-interface-devices.yaml are allowed for the image sensor, make them accepted by changing "additionalProperties: false" to "unevaluatedProperties: false" at the schema top-level. Signed-off-by: Jacopo Mondi Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml index e2470dd5920c7..60903da84e1f3 100644 --- a/Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml @@ -91,7 +91,7 @@ required: - vddd-supply - port -additionalProperties: false +unevaluatedProperties: false examples: - | -- GitLab From e2e73ed46c395777868b36c879c6cd213b45f123 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 6 Oct 2023 14:41:01 +0200 Subject: [PATCH 0545/1451] media: dt-bindings: sony,imx415: Allow props from video-interface-devices All the properties described by video-interface-devices.yaml are allowed for the image sensor, make them accepted by changing "additionalProperties: false" to "unevaluatedProperties: false" at the schema top-level. Because all properties are now accepted, there is no need to explicitly allow them in the schema. Signed-off-by: Jacopo Mondi Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../devicetree/bindings/media/i2c/sony,imx415.yaml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml index ffccf5f3c9e34..8ea3ddd251f62 100644 --- a/Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml @@ -44,14 +44,6 @@ properties: description: Sensor reset (XCLR) GPIO maxItems: 1 - flash-leds: true - - lens-focus: true - - orientation: true - - rotation: true - port: $ref: /schemas/graph.yaml#/$defs/port-base @@ -88,7 +80,7 @@ required: - ovdd-supply - port -additionalProperties: false +unevaluatedProperties: false examples: - | -- GitLab From ab75641ffd3a6a69ad5552a4cba2a20ff67e0904 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 3 Oct 2023 22:20:43 +0300 Subject: [PATCH 0546/1451] media: i2c: mt9m114: Fix missing error unwind in probe() Two paths in the probe function return directly instead of jumping to error handling. Fix them. Fixes: 24d756e914fc ("media: i2c: Add driver for onsemi MT9M114 camera sensor") Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/mt9m114.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/mt9m114.c b/drivers/media/i2c/mt9m114.c index dae675e523901..ac19078ceda3f 100644 --- a/drivers/media/i2c/mt9m114.c +++ b/drivers/media/i2c/mt9m114.c @@ -2367,7 +2367,7 @@ static int mt9m114_probe(struct i2c_client *client) ret = mt9m114_clk_init(sensor); if (ret) - return ret; + goto error_ep_free; /* * Identify the sensor. The driver supports runtime PM, but needs to @@ -2378,7 +2378,7 @@ static int mt9m114_probe(struct i2c_client *client) ret = mt9m114_power_on(sensor); if (ret < 0) { dev_err_probe(dev, ret, "Could not power on the device\n"); - return ret; + goto error_ep_free; } ret = mt9m114_identify(sensor); -- GitLab From 256b7767c97d94c8df46e1bf5bdb89a7f7dcac99 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 9 Oct 2023 09:40:11 +0300 Subject: [PATCH 0547/1451] media: ccs: Rework initialising sub-device state Initialise sub-device state in init_cfg callback using ccs_propagate() to the extent it covers of the initialisation. This fixes a bug where the driver configuration was incorrectly initialised. Fixes: d8bca3ed1d70 ("media: ccs: Use sub-device active state") Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ccs/ccs-core.c | 45 ++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 2abfd5932e027..14e89ae982947 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -2075,6 +2075,7 @@ static void ccs_propagate(struct v4l2_subdev *subdev, struct ccs_sensor *sensor = to_ccs_sensor(subdev); struct ccs_subdev *ssd = to_ccs_subdev(subdev); struct v4l2_rect *comp, *crops[CCS_PADS]; + struct v4l2_mbus_framefmt *fmt; ccs_get_crop_compose(subdev, sd_state, crops, &comp); @@ -2096,6 +2097,9 @@ static void ccs_propagate(struct v4l2_subdev *subdev, fallthrough; case V4L2_SEL_TGT_COMPOSE: *crops[CCS_PAD_SRC] = *comp; + fmt = v4l2_subdev_get_pad_format(subdev, sd_state, CCS_PAD_SRC); + fmt->width = comp->width; + fmt->height = comp->height; if (which == V4L2_SUBDEV_FORMAT_ACTIVE && ssd == sensor->src) sensor->src_src = *crops[CCS_PAD_SRC]; break; @@ -3003,31 +3007,38 @@ static int ccs_init_cfg(struct v4l2_subdev *sd, { struct ccs_subdev *ssd = to_ccs_subdev(sd); struct ccs_sensor *sensor = ssd->sensor; - unsigned int i; + unsigned int pad = ssd == sensor->pixel_array ? + CCS_PA_PAD_SRC : CCS_PAD_SINK; + struct v4l2_mbus_framefmt *fmt = + v4l2_subdev_get_pad_format(sd, sd_state, pad); + struct v4l2_rect *crop = + v4l2_subdev_get_pad_crop(sd, sd_state, pad); + bool is_active = !sd->active_state || sd->active_state == sd_state; mutex_lock(&sensor->mutex); - for (i = 0; i < ssd->npads; i++) { - struct v4l2_mbus_framefmt *fmt = - v4l2_subdev_get_pad_format(sd, sd_state, i); - struct v4l2_rect *crop = - v4l2_subdev_get_pad_crop(sd, sd_state, i); - struct v4l2_rect *comp; - - ccs_get_native_size(ssd, crop); + ccs_get_native_size(ssd, crop); - fmt->width = crop->width; - fmt->height = crop->height; - fmt->code = sensor->internal_csi_format->code; - fmt->field = V4L2_FIELD_NONE; + fmt->width = crop->width; + fmt->height = crop->height; + fmt->code = sensor->internal_csi_format->code; + fmt->field = V4L2_FIELD_NONE; - if (ssd == sensor->pixel_array) - continue; + if (ssd == sensor->pixel_array) { + if (is_active) + sensor->pa_src = *crop; - comp = v4l2_subdev_get_pad_compose(sd, sd_state, i); - *comp = *crop; + mutex_unlock(&sensor->mutex); + return 0; } + fmt = v4l2_subdev_get_pad_format(sd, sd_state, CCS_PAD_SRC); + fmt->code = ssd == sensor->src ? + sensor->csi_format->code : sensor->internal_csi_format->code; + fmt->field = V4L2_FIELD_NONE; + + ccs_propagate(sd, sd_state, is_active, V4L2_SEL_TGT_CROP); + mutex_unlock(&sensor->mutex); return 0; -- GitLab From 827804d6d7608cb797e689eabe6e200fa9fb58e6 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 9 Oct 2023 14:54:57 +0300 Subject: [PATCH 0548/1451] media: ccs: Fix a (harmless) lockdep warning The v4l2_subdev_init_finalize() is a macro that creates an unique lockdep key and name. As the CCS driver initialises all three of its sub-devices using the same call site, this creates a lockdep warning. Address it. Fixes: d8bca3ed1d70 ("media: ccs: Use sub-device active state") Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/i2c/ccs/ccs-core.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 14e89ae982947..12e6f0a26fc81 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -2955,7 +2955,9 @@ static void ccs_cleanup(struct ccs_sensor *sensor) static int ccs_init_subdev(struct ccs_sensor *sensor, struct ccs_subdev *ssd, const char *name, - unsigned short num_pads, u32 function) + unsigned short num_pads, u32 function, + const char *lock_name, + struct lock_class_key *lock_key) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); int rval; @@ -2993,7 +2995,7 @@ static int ccs_init_subdev(struct ccs_sensor *sensor, return rval; } - rval = v4l2_subdev_init_finalize(&ssd->sd); + rval = __v4l2_subdev_init_finalize(&ssd->sd, lock_name, lock_key); if (rval) { media_entity_cleanup(&ssd->sd.entity); return rval; @@ -3206,6 +3208,8 @@ static int ccs_firmware_name(struct i2c_client *client, static int ccs_probe(struct i2c_client *client) { + static struct lock_class_key pixel_array_lock_key, binner_lock_key, + scaler_lock_key; const struct ccs_device *ccsdev = device_get_match_data(&client->dev); struct ccs_sensor *sensor; const struct firmware *fw; @@ -3489,15 +3493,18 @@ static int ccs_probe(struct i2c_client *client) } rval = ccs_init_subdev(sensor, sensor->scaler, " scaler", 2, - MEDIA_ENT_F_PROC_VIDEO_SCALER); + MEDIA_ENT_F_PROC_VIDEO_SCALER, + "ccs scaler mutex", &scaler_lock_key); if (rval) goto out_cleanup; rval = ccs_init_subdev(sensor, sensor->binner, " binner", 2, - MEDIA_ENT_F_PROC_VIDEO_SCALER); + MEDIA_ENT_F_PROC_VIDEO_SCALER, + "ccs binner mutex", &binner_lock_key); if (rval) goto out_cleanup; rval = ccs_init_subdev(sensor, sensor->pixel_array, " pixel_array", 1, - MEDIA_ENT_F_CAM_SENSOR); + MEDIA_ENT_F_CAM_SENSOR, "ccs pixel array mutex", + &pixel_array_lock_key); if (rval) goto out_cleanup; -- GitLab From fa6df857fe7237f0cd97cab7355499dc1fd029e9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 8 Feb 2023 12:00:02 +0200 Subject: [PATCH 0549/1451] media: MAINTAINERS: Add co-maintainer for the rkisp1 driver As I'm actively working on the rkisp1 driver, I would like to volunteer as a co-maintainer, mostly to make sure I get CC on patches. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Reviewed-by: Sakari Ailus Signed-off-by: Hans Verkuil --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 65cc6a982de95..3b47e0b568595 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18539,6 +18539,7 @@ F: sound/soc/rockchip/rockchip_i2s_tdm.* ROCKCHIP ISP V1 DRIVER M: Dafna Hirschfeld +M: Laurent Pinchart L: linux-media@vger.kernel.org L: linux-rockchip@lists.infradead.org S: Maintained -- GitLab From 88f870f6ecc410b4de6d75c1e1b82c3ad38a3a39 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 26 Jan 2023 03:10:01 +0200 Subject: [PATCH 0550/1451] media: rkisp1: resizer: Use V4L2 subdev active state Use the V4L2 subdev active state API to store the active format and crop rectangle. This simplifies the driver not only by dropping the state stored in the rkisp1_resizer structure, but also by replacing the ops_lock with the state lock. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Elder Reviewed-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../platform/rockchip/rkisp1/rkisp1-common.h | 6 - .../platform/rockchip/rkisp1/rkisp1-resizer.c | 184 +++++++----------- 2 files changed, 66 insertions(+), 124 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index d30f0ecb1bfd8..5a03e460e08df 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -390,10 +390,7 @@ struct rkisp1_params { * @id: id of the resizer, one of RKISP1_SELFPATH, RKISP1_MAINPATH * @rkisp1: pointer to the rkisp1 device * @pads: media pads - * @pad_cfg: configurations for the pads * @config: the set of registers to configure the resizer - * @pixel_enc: pixel encoding of the resizer - * @ops_lock: a lock for the subdev ops */ struct rkisp1_resizer { struct v4l2_subdev sd; @@ -401,10 +398,7 @@ struct rkisp1_resizer { enum rkisp1_stream_id id; struct rkisp1_device *rkisp1; struct media_pad pads[RKISP1_RSZ_PAD_MAX]; - struct v4l2_subdev_pad_config pad_cfg[RKISP1_RSZ_PAD_MAX]; const struct rkisp1_rsz_config *config; - enum v4l2_pixel_encoding pixel_enc; - struct mutex ops_lock; /* serialize the subdevice ops */ }; /* diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c index c15ae0218118c..6845df38ef5fe 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c @@ -117,34 +117,6 @@ static inline void rkisp1_rsz_write(struct rkisp1_resizer *rsz, u32 offset, rkisp1_write(rsz->rkisp1, rsz->regs_base + offset, value); } -static struct v4l2_mbus_framefmt * -rkisp1_rsz_get_pad_fmt(struct rkisp1_resizer *rsz, - struct v4l2_subdev_state *sd_state, - unsigned int pad, u32 which) -{ - struct v4l2_subdev_state state = { - .pads = rsz->pad_cfg, - }; - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&rsz->sd, sd_state, pad); - else - return v4l2_subdev_get_try_format(&rsz->sd, &state, pad); -} - -static struct v4l2_rect * -rkisp1_rsz_get_pad_crop(struct rkisp1_resizer *rsz, - struct v4l2_subdev_state *sd_state, - unsigned int pad, u32 which) -{ - struct v4l2_subdev_state state = { - .pads = rsz->pad_cfg, - }; - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(&rsz->sd, sd_state, pad); - else - return v4l2_subdev_get_try_crop(&rsz->sd, &state, pad); -} - /* ---------------------------------------------------------------------------- * Dual crop hw configs */ @@ -165,17 +137,18 @@ static void rkisp1_dcrop_disable(struct rkisp1_resizer *rsz, } /* configure dual-crop unit */ -static void rkisp1_dcrop_config(struct rkisp1_resizer *rsz) +static void rkisp1_dcrop_config(struct rkisp1_resizer *rsz, + struct v4l2_subdev_state *sd_state) { struct rkisp1_device *rkisp1 = rsz->rkisp1; struct v4l2_mbus_framefmt *sink_fmt; struct v4l2_rect *sink_crop; u32 dc_ctrl; - sink_crop = rkisp1_rsz_get_pad_crop(rsz, NULL, RKISP1_RSZ_PAD_SINK, - V4L2_SUBDEV_FORMAT_ACTIVE); - sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, NULL, RKISP1_RSZ_PAD_SINK, - V4L2_SUBDEV_FORMAT_ACTIVE); + sink_crop = v4l2_subdev_get_pad_crop(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SINK); + sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SINK); if (sink_crop->width == sink_fmt->width && sink_crop->height == sink_fmt->height && @@ -296,6 +269,7 @@ static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz, } static void rkisp1_rsz_config(struct rkisp1_resizer *rsz, + struct v4l2_subdev_state *sd_state, enum rkisp1_shadow_regs_when when) { const struct rkisp1_rsz_yuv_mbus_info *sink_yuv_info, *src_yuv_info; @@ -303,20 +277,21 @@ static void rkisp1_rsz_config(struct rkisp1_resizer *rsz, struct v4l2_mbus_framefmt *src_fmt, *sink_fmt; struct v4l2_rect *sink_crop; - sink_crop = rkisp1_rsz_get_pad_crop(rsz, NULL, RKISP1_RSZ_PAD_SINK, - V4L2_SUBDEV_FORMAT_ACTIVE); - src_fmt = rkisp1_rsz_get_pad_fmt(rsz, NULL, RKISP1_RSZ_PAD_SRC, - V4L2_SUBDEV_FORMAT_ACTIVE); - src_yuv_info = rkisp1_rsz_get_yuv_mbus_info(src_fmt->code); - sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, NULL, RKISP1_RSZ_PAD_SINK, - V4L2_SUBDEV_FORMAT_ACTIVE); + sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SINK); + sink_crop = v4l2_subdev_get_pad_crop(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SINK); + src_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SRC); + sink_yuv_info = rkisp1_rsz_get_yuv_mbus_info(sink_fmt->code); + src_yuv_info = rkisp1_rsz_get_yuv_mbus_info(src_fmt->code); /* * The resizer only works on yuv formats, * so return if it is bayer format. */ - if (rsz->pixel_enc == V4L2_PIXEL_ENC_BAYER) { + if (!sink_yuv_info) { rkisp1_rsz_disable(rsz, when); return; } @@ -405,7 +380,7 @@ static int rkisp1_rsz_init_config(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; struct v4l2_rect *sink_crop; - sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, + sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_RSZ_PAD_SRC); sink_fmt->width = RKISP1_DEFAULT_WIDTH; sink_fmt->height = RKISP1_DEFAULT_HEIGHT; @@ -423,7 +398,7 @@ static int rkisp1_rsz_init_config(struct v4l2_subdev *sd, sink_crop->left = 0; sink_crop->top = 0; - src_fmt = v4l2_subdev_get_try_format(sd, sd_state, + src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_RSZ_PAD_SINK); *src_fmt = *sink_fmt; @@ -434,16 +409,16 @@ static int rkisp1_rsz_init_config(struct v4l2_subdev *sd, static void rkisp1_rsz_set_src_fmt(struct rkisp1_resizer *rsz, struct v4l2_subdev_state *sd_state, - struct v4l2_mbus_framefmt *format, - unsigned int which) + struct v4l2_mbus_framefmt *format) { const struct rkisp1_mbus_info *sink_mbus_info; struct v4l2_mbus_framefmt *src_fmt, *sink_fmt; - sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SINK, - which); - src_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SRC, - which); + sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SINK); + src_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SRC); + sink_mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); /* for YUV formats, userspace can change the mbus code on the src pad if it is supported */ @@ -463,18 +438,16 @@ static void rkisp1_rsz_set_src_fmt(struct rkisp1_resizer *rsz, static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz, struct v4l2_subdev_state *sd_state, - struct v4l2_rect *r, - unsigned int which) + struct v4l2_rect *r) { const struct rkisp1_mbus_info *mbus_info; struct v4l2_mbus_framefmt *sink_fmt; struct v4l2_rect *sink_crop; - sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SINK, - which); - sink_crop = rkisp1_rsz_get_pad_crop(rsz, sd_state, - RKISP1_RSZ_PAD_SINK, - which); + sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SINK); + sink_crop = v4l2_subdev_get_pad_crop(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SINK); /* Not crop for MP bayer raw data */ mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); @@ -501,21 +474,20 @@ static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz, static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz, struct v4l2_subdev_state *sd_state, - struct v4l2_mbus_framefmt *format, - unsigned int which) + struct v4l2_mbus_framefmt *format) { const struct rkisp1_mbus_info *mbus_info; struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; struct v4l2_rect *sink_crop; bool is_yuv; - sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SINK, - which); - src_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SRC, - which); - sink_crop = rkisp1_rsz_get_pad_crop(rsz, sd_state, - RKISP1_RSZ_PAD_SINK, - which); + sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SINK); + src_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SRC); + sink_crop = v4l2_subdev_get_pad_crop(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SINK); + if (rsz->id == RKISP1_SELFPATH) sink_fmt->code = MEDIA_BUS_FMT_YUYV8_2X8; else @@ -526,8 +498,6 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz, sink_fmt->code = RKISP1_DEF_FMT; mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); } - if (which == V4L2_SUBDEV_FORMAT_ACTIVE) - rsz->pixel_enc = mbus_info->pixel_enc; sink_fmt->width = clamp_t(u32, format->width, RKISP1_ISP_MIN_WIDTH, @@ -576,21 +546,7 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz, src_fmt->quantization = sink_fmt->quantization; /* Update sink crop */ - rkisp1_rsz_set_sink_crop(rsz, sd_state, sink_crop, which); -} - -static int rkisp1_rsz_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct rkisp1_resizer *rsz = - container_of(sd, struct rkisp1_resizer, sd); - - mutex_lock(&rsz->ops_lock); - fmt->format = *rkisp1_rsz_get_pad_fmt(rsz, sd_state, fmt->pad, - fmt->which); - mutex_unlock(&rsz->ops_lock); - return 0; + rkisp1_rsz_set_sink_crop(rsz, sd_state, sink_crop); } static int rkisp1_rsz_set_fmt(struct v4l2_subdev *sd, @@ -600,15 +556,11 @@ static int rkisp1_rsz_set_fmt(struct v4l2_subdev *sd, struct rkisp1_resizer *rsz = container_of(sd, struct rkisp1_resizer, sd); - mutex_lock(&rsz->ops_lock); if (fmt->pad == RKISP1_RSZ_PAD_SINK) - rkisp1_rsz_set_sink_fmt(rsz, sd_state, &fmt->format, - fmt->which); + rkisp1_rsz_set_sink_fmt(rsz, sd_state, &fmt->format); else - rkisp1_rsz_set_src_fmt(rsz, sd_state, &fmt->format, - fmt->which); + rkisp1_rsz_set_src_fmt(rsz, sd_state, &fmt->format); - mutex_unlock(&rsz->ops_lock); return 0; } @@ -616,35 +568,32 @@ static int rkisp1_rsz_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { - struct rkisp1_resizer *rsz = - container_of(sd, struct rkisp1_resizer, sd); struct v4l2_mbus_framefmt *mf_sink; int ret = 0; if (sel->pad == RKISP1_RSZ_PAD_SRC) return -EINVAL; - mutex_lock(&rsz->ops_lock); switch (sel->target) { case V4L2_SEL_TGT_CROP_BOUNDS: - mf_sink = rkisp1_rsz_get_pad_fmt(rsz, sd_state, - RKISP1_RSZ_PAD_SINK, - sel->which); + mf_sink = v4l2_subdev_get_pad_format(sd, sd_state, + RKISP1_RSZ_PAD_SINK); sel->r.height = mf_sink->height; sel->r.width = mf_sink->width; sel->r.left = 0; sel->r.top = 0; break; + case V4L2_SEL_TGT_CROP: - sel->r = *rkisp1_rsz_get_pad_crop(rsz, sd_state, - RKISP1_RSZ_PAD_SINK, - sel->which); + sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, + RKISP1_RSZ_PAD_SINK); break; + default: ret = -EINVAL; + break; } - mutex_unlock(&rsz->ops_lock); return ret; } @@ -661,9 +610,7 @@ static int rkisp1_rsz_set_selection(struct v4l2_subdev *sd, dev_dbg(rsz->rkisp1->dev, "%s: pad: %d sel(%d,%d)/%dx%d\n", __func__, sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height); - mutex_lock(&rsz->ops_lock); - rkisp1_rsz_set_sink_crop(rsz, sd_state, &sel->r, sel->which); - mutex_unlock(&rsz->ops_lock); + rkisp1_rsz_set_sink_crop(rsz, sd_state, &sel->r); return 0; } @@ -677,7 +624,7 @@ static const struct v4l2_subdev_pad_ops rkisp1_rsz_pad_ops = { .get_selection = rkisp1_rsz_get_selection, .set_selection = rkisp1_rsz_set_selection, .init_cfg = rkisp1_rsz_init_config, - .get_fmt = rkisp1_rsz_get_fmt, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = rkisp1_rsz_set_fmt, .link_validate = v4l2_subdev_link_validate_default, }; @@ -693,6 +640,7 @@ static int rkisp1_rsz_s_stream(struct v4l2_subdev *sd, int enable) struct rkisp1_device *rkisp1 = rsz->rkisp1; struct rkisp1_capture *other = &rkisp1->capture_devs[rsz->id ^ 1]; enum rkisp1_shadow_regs_when when = RKISP1_SHADOW_REGS_SYNC; + struct v4l2_subdev_state *sd_state; if (!enable) { rkisp1_dcrop_disable(rsz, RKISP1_SHADOW_REGS_ASYNC); @@ -703,11 +651,13 @@ static int rkisp1_rsz_s_stream(struct v4l2_subdev *sd, int enable) if (other->is_streaming) when = RKISP1_SHADOW_REGS_ASYNC; - mutex_lock(&rsz->ops_lock); - rkisp1_rsz_config(rsz, when); - rkisp1_dcrop_config(rsz); + sd_state = v4l2_subdev_lock_and_get_active_state(sd); + + rkisp1_rsz_config(rsz, sd_state, when); + rkisp1_dcrop_config(rsz, sd_state); + + v4l2_subdev_unlock_state(sd_state); - mutex_unlock(&rsz->ops_lock); return 0; } @@ -726,15 +676,12 @@ static void rkisp1_rsz_unregister(struct rkisp1_resizer *rsz) return; v4l2_device_unregister_subdev(&rsz->sd); + v4l2_subdev_cleanup(&rsz->sd); media_entity_cleanup(&rsz->sd.entity); - mutex_destroy(&rsz->ops_lock); } static int rkisp1_rsz_register(struct rkisp1_resizer *rsz) { - struct v4l2_subdev_state state = { - .pads = rsz->pad_cfg, - }; static const char * const dev_names[] = { RKISP1_RSZ_MP_DEV_NAME, RKISP1_RSZ_SP_DEV_NAME @@ -763,25 +710,26 @@ static int rkisp1_rsz_register(struct rkisp1_resizer *rsz) pads[RKISP1_RSZ_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT; - rsz->pixel_enc = RKISP1_DEF_PIXEL_ENC; - - mutex_init(&rsz->ops_lock); ret = media_entity_pads_init(&sd->entity, RKISP1_RSZ_PAD_MAX, pads); if (ret) - goto error; + goto err_entity_cleanup; + + ret = v4l2_subdev_init_finalize(sd); + if (ret) + goto err_entity_cleanup; ret = v4l2_device_register_subdev(&rsz->rkisp1->v4l2_dev, sd); if (ret) { dev_err(sd->dev, "Failed to register resizer subdev\n"); - goto error; + goto err_subdev_cleanup; } - rkisp1_rsz_init_config(sd, &state); return 0; -error: +err_subdev_cleanup: + v4l2_subdev_cleanup(sd); +err_entity_cleanup: media_entity_cleanup(&sd->entity); - mutex_destroy(&rsz->ops_lock); return ret; } -- GitLab From 2cce0a369dbdb59d806f9c0c3599ff74a864c0f4 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 26 Jan 2023 03:10:01 +0200 Subject: [PATCH 0551/1451] media: rkisp1: isp: Use V4L2 subdev active state Use the V4L2 subdev active state API to store the active format and crop rectangle. This simplifies the driver not only by dropping the state stored in the rkisp1_isp structure, but also by replacing the ops_lock with the state lock. The rkisp1_isp.sink_fmt field needs to be kept, as it is accessed from the stats interrupt handler. To simplify the rkisp1_isp_set_sink_fmt() implementation, the field is now set when starting the ISP, instead of when setting the format. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Elder Reviewed-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../platform/rockchip/rkisp1/rkisp1-common.h | 6 - .../platform/rockchip/rkisp1/rkisp1-isp.c | 261 +++++++----------- 2 files changed, 102 insertions(+), 165 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index 5a03e460e08df..053ce04066b65 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -190,20 +190,14 @@ struct rkisp1_csi { * @sd: v4l2_subdev variable * @rkisp1: pointer to rkisp1_device * @pads: media pads - * @pad_cfg: pads configurations * @sink_fmt: input format - * @src_fmt: output format - * @ops_lock: ops serialization * @frame_sequence: used to synchronize frame_id between video devices. */ struct rkisp1_isp { struct v4l2_subdev sd; struct rkisp1_device *rkisp1; struct media_pad pads[RKISP1_ISP_PAD_MAX]; - struct v4l2_subdev_pad_config pad_cfg[RKISP1_ISP_PAD_MAX]; const struct rkisp1_mbus_info *sink_fmt; - const struct rkisp1_mbus_info *src_fmt; - struct mutex ops_lock; /* serialize the subdevice ops */ __u32 frame_sequence; }; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index 07fbb77ce2349..88ca8b2283b7f 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -53,40 +53,6 @@ * +---------------------------------------------------------+ */ -/* ---------------------------------------------------------------------------- - * Helpers - */ - -static struct v4l2_mbus_framefmt * -rkisp1_isp_get_pad_fmt(struct rkisp1_isp *isp, - struct v4l2_subdev_state *sd_state, - unsigned int pad, u32 which) -{ - struct v4l2_subdev_state state = { - .pads = isp->pad_cfg - }; - - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&isp->sd, sd_state, pad); - else - return v4l2_subdev_get_try_format(&isp->sd, &state, pad); -} - -static struct v4l2_rect * -rkisp1_isp_get_pad_crop(struct rkisp1_isp *isp, - struct v4l2_subdev_state *sd_state, - unsigned int pad, u32 which) -{ - struct v4l2_subdev_state state = { - .pads = isp->pad_cfg - }; - - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(&isp->sd, sd_state, pad); - else - return v4l2_subdev_get_try_crop(&isp->sd, &state, pad); -} - /* ---------------------------------------------------------------------------- * Camera Interface registers configurations */ @@ -96,12 +62,12 @@ rkisp1_isp_get_pad_crop(struct rkisp1_isp *isp, * This should only be called when configuring CIF * or at the frame end interrupt */ -static void rkisp1_config_ism(struct rkisp1_isp *isp) +static void rkisp1_config_ism(struct rkisp1_isp *isp, + struct v4l2_subdev_state *sd_state) { const struct v4l2_rect *src_crop = - rkisp1_isp_get_pad_crop(isp, NULL, - RKISP1_ISP_PAD_SOURCE_VIDEO, - V4L2_SUBDEV_FORMAT_ACTIVE); + v4l2_subdev_get_pad_crop(&isp->sd, sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); struct rkisp1_device *rkisp1 = isp->rkisp1; u32 val; @@ -125,21 +91,26 @@ static void rkisp1_config_ism(struct rkisp1_isp *isp) * configure ISP blocks with input format, size...... */ static int rkisp1_config_isp(struct rkisp1_isp *isp, + struct v4l2_subdev_state *sd_state, enum v4l2_mbus_type mbus_type, u32 mbus_flags) { struct rkisp1_device *rkisp1 = isp->rkisp1; u32 isp_ctrl = 0, irq_mask = 0, acq_mult = 0, acq_prop = 0; - const struct rkisp1_mbus_info *sink_fmt = isp->sink_fmt; - const struct rkisp1_mbus_info *src_fmt = isp->src_fmt; + const struct rkisp1_mbus_info *sink_fmt; + const struct rkisp1_mbus_info *src_fmt; + const struct v4l2_mbus_framefmt *src_frm; const struct v4l2_mbus_framefmt *sink_frm; const struct v4l2_rect *sink_crop; - sink_frm = rkisp1_isp_get_pad_fmt(isp, NULL, - RKISP1_ISP_PAD_SINK_VIDEO, - V4L2_SUBDEV_FORMAT_ACTIVE); - sink_crop = rkisp1_isp_get_pad_crop(isp, NULL, - RKISP1_ISP_PAD_SINK_VIDEO, - V4L2_SUBDEV_FORMAT_ACTIVE); + sink_frm = v4l2_subdev_get_pad_format(&isp->sd, sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); + sink_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); + src_frm = v4l2_subdev_get_pad_format(&isp->sd, sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); + + sink_fmt = rkisp1_mbus_info_get_by_code(sink_frm->code); + src_fmt = rkisp1_mbus_info_get_by_code(src_frm->code); if (sink_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) { acq_mult = 1; @@ -230,14 +201,15 @@ static int rkisp1_config_isp(struct rkisp1_isp *isp, } else { struct v4l2_mbus_framefmt *src_frm; - src_frm = rkisp1_isp_get_pad_fmt(isp, NULL, - RKISP1_ISP_PAD_SOURCE_VIDEO, - V4L2_SUBDEV_FORMAT_ACTIVE); + src_frm = v4l2_subdev_get_pad_format(&isp->sd, sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); rkisp1_params_pre_configure(&rkisp1->params, sink_fmt->bayer_pat, src_frm->quantization, src_frm->ycbcr_enc); } + isp->sink_fmt = sink_fmt; + return 0; } @@ -258,16 +230,17 @@ static void rkisp1_config_path(struct rkisp1_isp *isp, /* Hardware configure Entry */ static int rkisp1_config_cif(struct rkisp1_isp *isp, + struct v4l2_subdev_state *sd_state, enum v4l2_mbus_type mbus_type, u32 mbus_flags) { int ret; - ret = rkisp1_config_isp(isp, mbus_type, mbus_flags); + ret = rkisp1_config_isp(isp, sd_state, mbus_type, mbus_flags); if (ret) return ret; rkisp1_config_path(isp, mbus_type); - rkisp1_config_ism(isp); + rkisp1_config_ism(isp, sd_state); return 0; } @@ -328,9 +301,12 @@ static void rkisp1_config_clk(struct rkisp1_isp *isp) } } -static void rkisp1_isp_start(struct rkisp1_isp *isp) +static void rkisp1_isp_start(struct rkisp1_isp *isp, + struct v4l2_subdev_state *sd_state) { struct rkisp1_device *rkisp1 = isp->rkisp1; + const struct v4l2_mbus_framefmt *src_fmt; + const struct rkisp1_mbus_info *src_info; u32 val; rkisp1_config_clk(isp); @@ -342,7 +318,11 @@ static void rkisp1_isp_start(struct rkisp1_isp *isp) RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE; rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val); - if (isp->src_fmt->pixel_enc != V4L2_PIXEL_ENC_BAYER) + src_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); + src_info = rkisp1_mbus_info_get_by_code(src_fmt->code); + + if (src_info->pixel_enc != V4L2_PIXEL_ENC_BAYER) rkisp1_params_post_configure(&rkisp1->params); } @@ -436,7 +416,7 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd, struct v4l2_rect *sink_crop, *src_crop; /* Video. */ - sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, + sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_ISP_PAD_SINK_VIDEO); sink_fmt->width = RKISP1_DEFAULT_WIDTH; sink_fmt->height = RKISP1_DEFAULT_HEIGHT; @@ -447,14 +427,14 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd, sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; - sink_crop = v4l2_subdev_get_try_crop(sd, sd_state, + sink_crop = v4l2_subdev_get_pad_crop(sd, sd_state, RKISP1_ISP_PAD_SINK_VIDEO); sink_crop->width = RKISP1_DEFAULT_WIDTH; sink_crop->height = RKISP1_DEFAULT_HEIGHT; sink_crop->left = 0; sink_crop->top = 0; - src_fmt = v4l2_subdev_get_try_format(sd, sd_state, + src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_ISP_PAD_SOURCE_VIDEO); *src_fmt = *sink_fmt; src_fmt->code = RKISP1_DEF_SRC_PAD_FMT; @@ -463,14 +443,14 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd, src_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; src_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; - src_crop = v4l2_subdev_get_try_crop(sd, sd_state, + src_crop = v4l2_subdev_get_pad_crop(sd, sd_state, RKISP1_ISP_PAD_SOURCE_VIDEO); *src_crop = *sink_crop; /* Parameters and statistics. */ - sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, + sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_ISP_PAD_SINK_PARAMS); - src_fmt = v4l2_subdev_get_try_format(sd, sd_state, + src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_ISP_PAD_SOURCE_STATS); sink_fmt->width = 0; sink_fmt->height = 0; @@ -483,8 +463,7 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd, static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp, struct v4l2_subdev_state *sd_state, - struct v4l2_mbus_framefmt *format, - unsigned int which) + struct v4l2_mbus_framefmt *format) { const struct rkisp1_mbus_info *sink_info; const struct rkisp1_mbus_info *src_info; @@ -493,12 +472,12 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp, const struct v4l2_rect *src_crop; bool set_csc; - sink_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO, which); - src_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO, which); - src_crop = rkisp1_isp_get_pad_crop(isp, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO, which); + sink_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); + src_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); + src_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); /* * Media bus code. The ISP can operate in pass-through mode (Bayer in, @@ -581,26 +560,20 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp, */ if (set_csc) format->flags |= V4L2_MBUS_FRAMEFMT_SET_CSC; - - /* Store the source format info when setting the active format. */ - if (which == V4L2_SUBDEV_FORMAT_ACTIVE) - isp->src_fmt = src_info; } static void rkisp1_isp_set_src_crop(struct rkisp1_isp *isp, struct v4l2_subdev_state *sd_state, - struct v4l2_rect *r, unsigned int which) + struct v4l2_rect *r) { struct v4l2_mbus_framefmt *src_fmt; const struct v4l2_rect *sink_crop; struct v4l2_rect *src_crop; - src_crop = rkisp1_isp_get_pad_crop(isp, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO, - which); - sink_crop = rkisp1_isp_get_pad_crop(isp, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO, - which); + src_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); + sink_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); src_crop->left = ALIGN(r->left, 2); src_crop->width = ALIGN(r->width, 2); @@ -611,24 +584,22 @@ static void rkisp1_isp_set_src_crop(struct rkisp1_isp *isp, *r = *src_crop; /* Propagate to out format */ - src_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO, which); - rkisp1_isp_set_src_fmt(isp, sd_state, src_fmt, which); + src_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); + rkisp1_isp_set_src_fmt(isp, sd_state, src_fmt); } static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp, struct v4l2_subdev_state *sd_state, - struct v4l2_rect *r, unsigned int which) + struct v4l2_rect *r) { struct v4l2_rect *sink_crop, *src_crop; const struct v4l2_mbus_framefmt *sink_fmt; - sink_crop = rkisp1_isp_get_pad_crop(isp, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO, - which); - sink_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO, - which); + sink_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); + sink_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); sink_crop->left = ALIGN(r->left, 2); sink_crop->width = ALIGN(r->width, 2); @@ -639,32 +610,28 @@ static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp, *r = *sink_crop; /* Propagate to out crop */ - src_crop = rkisp1_isp_get_pad_crop(isp, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO, which); - rkisp1_isp_set_src_crop(isp, sd_state, src_crop, which); + src_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); + rkisp1_isp_set_src_crop(isp, sd_state, src_crop); } static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp, struct v4l2_subdev_state *sd_state, - struct v4l2_mbus_framefmt *format, - unsigned int which) + struct v4l2_mbus_framefmt *format) { const struct rkisp1_mbus_info *mbus_info; struct v4l2_mbus_framefmt *sink_fmt; struct v4l2_rect *sink_crop; bool is_yuv; - sink_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO, - which); + sink_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); sink_fmt->code = format->code; mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SINK)) { sink_fmt->code = RKISP1_DEF_SINK_PAD_FMT; mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); } - if (which == V4L2_SUBDEV_FORMAT_ACTIVE) - isp->sink_fmt = mbus_info; sink_fmt->width = clamp_t(u32, format->width, RKISP1_ISP_MIN_WIDTH, @@ -706,23 +673,9 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp, *format = *sink_fmt; /* Propagate to in crop */ - sink_crop = rkisp1_isp_get_pad_crop(isp, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO, - which); - rkisp1_isp_set_sink_crop(isp, sd_state, sink_crop, which); -} - -static int rkisp1_isp_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct rkisp1_isp *isp = to_rkisp1_isp(sd); - - mutex_lock(&isp->ops_lock); - fmt->format = *rkisp1_isp_get_pad_fmt(isp, sd_state, fmt->pad, - fmt->which); - mutex_unlock(&isp->ops_lock); - return 0; + sink_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); + rkisp1_isp_set_sink_crop(isp, sd_state, sink_crop); } static int rkisp1_isp_set_fmt(struct v4l2_subdev *sd, @@ -731,18 +684,13 @@ static int rkisp1_isp_set_fmt(struct v4l2_subdev *sd, { struct rkisp1_isp *isp = to_rkisp1_isp(sd); - mutex_lock(&isp->ops_lock); if (fmt->pad == RKISP1_ISP_PAD_SINK_VIDEO) - rkisp1_isp_set_sink_fmt(isp, sd_state, &fmt->format, - fmt->which); + rkisp1_isp_set_sink_fmt(isp, sd_state, &fmt->format); else if (fmt->pad == RKISP1_ISP_PAD_SOURCE_VIDEO) - rkisp1_isp_set_src_fmt(isp, sd_state, &fmt->format, - fmt->which); + rkisp1_isp_set_src_fmt(isp, sd_state, &fmt->format); else - fmt->format = *rkisp1_isp_get_pad_fmt(isp, sd_state, fmt->pad, - fmt->which); + fmt->format = *v4l2_subdev_get_pad_format(sd, sd_state, fmt->pad); - mutex_unlock(&isp->ops_lock); return 0; } @@ -750,39 +698,37 @@ static int rkisp1_isp_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { - struct rkisp1_isp *isp = to_rkisp1_isp(sd); int ret = 0; if (sel->pad != RKISP1_ISP_PAD_SOURCE_VIDEO && sel->pad != RKISP1_ISP_PAD_SINK_VIDEO) return -EINVAL; - mutex_lock(&isp->ops_lock); switch (sel->target) { case V4L2_SEL_TGT_CROP_BOUNDS: if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO) { struct v4l2_mbus_framefmt *fmt; - fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, sel->pad, - sel->which); + fmt = v4l2_subdev_get_pad_format(sd, sd_state, sel->pad); sel->r.height = fmt->height; sel->r.width = fmt->width; sel->r.left = 0; sel->r.top = 0; } else { - sel->r = *rkisp1_isp_get_pad_crop(isp, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO, - sel->which); + sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); } break; + case V4L2_SEL_TGT_CROP: - sel->r = *rkisp1_isp_get_pad_crop(isp, sd_state, sel->pad, - sel->which); + sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, sel->pad); break; + default: ret = -EINVAL; + break; } - mutex_unlock(&isp->ops_lock); + return ret; } @@ -798,15 +744,14 @@ static int rkisp1_isp_set_selection(struct v4l2_subdev *sd, dev_dbg(isp->rkisp1->dev, "%s: pad: %d sel(%d,%d)/%dx%d\n", __func__, sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height); - mutex_lock(&isp->ops_lock); + if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO) - rkisp1_isp_set_sink_crop(isp, sd_state, &sel->r, sel->which); + rkisp1_isp_set_sink_crop(isp, sd_state, &sel->r); else if (sel->pad == RKISP1_ISP_PAD_SOURCE_VIDEO) - rkisp1_isp_set_src_crop(isp, sd_state, &sel->r, sel->which); + rkisp1_isp_set_src_crop(isp, sd_state, &sel->r); else ret = -EINVAL; - mutex_unlock(&isp->ops_lock); return ret; } @@ -824,7 +769,7 @@ static const struct v4l2_subdev_pad_ops rkisp1_isp_pad_ops = { .get_selection = rkisp1_isp_get_selection, .set_selection = rkisp1_isp_set_selection, .init_cfg = rkisp1_isp_init_config, - .get_fmt = rkisp1_isp_get_fmt, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = rkisp1_isp_set_fmt, .link_validate = v4l2_subdev_link_validate_default, }; @@ -837,6 +782,7 @@ static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable) { struct rkisp1_isp *isp = to_rkisp1_isp(sd); struct rkisp1_device *rkisp1 = isp->rkisp1; + struct v4l2_subdev_state *sd_state; struct media_pad *source_pad; struct media_pad *sink_pad; enum v4l2_mbus_type mbus_type; @@ -881,21 +827,23 @@ static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable) } isp->frame_sequence = -1; - mutex_lock(&isp->ops_lock); - ret = rkisp1_config_cif(isp, mbus_type, mbus_flags); + + sd_state = v4l2_subdev_lock_and_get_active_state(sd); + + ret = rkisp1_config_cif(isp, sd_state, mbus_type, mbus_flags); if (ret) - goto mutex_unlock; + goto out_unlock; - rkisp1_isp_start(isp); + rkisp1_isp_start(isp, sd_state); ret = v4l2_subdev_call(rkisp1->source, video, s_stream, true); if (ret) { rkisp1_isp_stop(isp); - goto mutex_unlock; + goto out_unlock; } -mutex_unlock: - mutex_unlock(&isp->ops_lock); +out_unlock: + v4l2_subdev_unlock_state(sd_state); return ret; } @@ -933,9 +881,6 @@ static const struct v4l2_subdev_ops rkisp1_isp_ops = { int rkisp1_isp_register(struct rkisp1_device *rkisp1) { - struct v4l2_subdev_state state = { - .pads = rkisp1->isp.pad_cfg - }; struct rkisp1_isp *isp = &rkisp1->isp; struct media_pad *pads = isp->pads; struct v4l2_subdev *sd = &isp->sd; @@ -956,27 +901,26 @@ int rkisp1_isp_register(struct rkisp1_device *rkisp1) pads[RKISP1_ISP_PAD_SOURCE_VIDEO].flags = MEDIA_PAD_FL_SOURCE; pads[RKISP1_ISP_PAD_SOURCE_STATS].flags = MEDIA_PAD_FL_SOURCE; - isp->sink_fmt = rkisp1_mbus_info_get_by_code(RKISP1_DEF_SINK_PAD_FMT); - isp->src_fmt = rkisp1_mbus_info_get_by_code(RKISP1_DEF_SRC_PAD_FMT); - - mutex_init(&isp->ops_lock); ret = media_entity_pads_init(&sd->entity, RKISP1_ISP_PAD_MAX, pads); if (ret) - goto error; + goto err_entity_cleanup; + + ret = v4l2_subdev_init_finalize(sd); + if (ret) + goto err_subdev_cleanup; ret = v4l2_device_register_subdev(&rkisp1->v4l2_dev, sd); if (ret) { dev_err(rkisp1->dev, "Failed to register isp subdev\n"); - goto error; + goto err_subdev_cleanup; } - rkisp1_isp_init_config(sd, &state); - return 0; -error: +err_subdev_cleanup: + v4l2_subdev_cleanup(sd); +err_entity_cleanup: media_entity_cleanup(&sd->entity); - mutex_destroy(&isp->ops_lock); isp->sd.v4l2_dev = NULL; return ret; } @@ -990,7 +934,6 @@ void rkisp1_isp_unregister(struct rkisp1_device *rkisp1) v4l2_device_unregister_subdev(&isp->sd); media_entity_cleanup(&isp->sd.entity); - mutex_destroy(&isp->ops_lock); } /* ---------------------------------------------------------------------------- -- GitLab From c7e26218820786d23d999ec9b33c812d07f98199 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 26 Jan 2023 03:10:01 +0200 Subject: [PATCH 0552/1451] media: rkisp1: csi: Use V4L2 subdev active state Use the V4L2 subdev active state API to store the active format and crop rectangle. This simplifies the driver not only by dropping the state stored in the rkisp1_csi structure, but also by replacing the ops_lock with the state lock. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Elder Reviewed-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../platform/rockchip/rkisp1/rkisp1-common.h | 6 - .../platform/rockchip/rkisp1/rkisp1-csi.c | 107 ++++++------------ 2 files changed, 33 insertions(+), 80 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index 053ce04066b65..1e7cea1bea5ea 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -167,9 +167,6 @@ struct rkisp1_sensor_async { * @is_dphy_errctrl_disabled: if dphy errctrl is disabled (avoid endless interrupt) * @sd: v4l2_subdev variable * @pads: media pads - * @pad_cfg: configurations for the pads - * @sink_fmt: input format - * @lock: protects pad_cfg and sink_fmt * @source: source in-use, set when starting streaming */ struct rkisp1_csi { @@ -178,9 +175,6 @@ struct rkisp1_csi { bool is_dphy_errctrl_disabled; struct v4l2_subdev sd; struct media_pad pads[RKISP1_CSI_PAD_NUM]; - struct v4l2_subdev_pad_config pad_cfg[RKISP1_CSI_PAD_NUM]; - const struct rkisp1_mbus_info *sink_fmt; - struct mutex lock; struct v4l2_subdev *source; }; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c index fdff3d0da4e50..6e17b2817e610 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c @@ -30,23 +30,6 @@ static inline struct rkisp1_csi *to_rkisp1_csi(struct v4l2_subdev *sd) return container_of(sd, struct rkisp1_csi, sd); } -static struct v4l2_mbus_framefmt * -rkisp1_csi_get_pad_fmt(struct rkisp1_csi *csi, - struct v4l2_subdev_state *sd_state, - unsigned int pad, u32 which) -{ - struct v4l2_subdev_state state = { - .pads = csi->pad_cfg - }; - - lockdep_assert_held(&csi->lock); - - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&csi->sd, sd_state, pad); - else - return v4l2_subdev_get_try_format(&csi->sd, &state, pad); -} - int rkisp1_csi_link_sensor(struct rkisp1_device *rkisp1, struct v4l2_subdev *sd, struct rkisp1_sensor_async *s_asd, unsigned int source_pad) @@ -76,7 +59,8 @@ int rkisp1_csi_link_sensor(struct rkisp1_device *rkisp1, struct v4l2_subdev *sd, } static int rkisp1_csi_config(struct rkisp1_csi *csi, - const struct rkisp1_sensor_async *sensor) + const struct rkisp1_sensor_async *sensor, + const struct rkisp1_mbus_info *format) { struct rkisp1_device *rkisp1 = csi->rkisp1; unsigned int lanes = sensor->lanes; @@ -98,7 +82,7 @@ static int rkisp1_csi_config(struct rkisp1_csi *csi, /* Configure Data Type and Virtual Channel */ rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMG_DATA_SEL, - RKISP1_CIF_MIPI_DATA_SEL_DT(csi->sink_fmt->mipi_dt) | + RKISP1_CIF_MIPI_DATA_SEL_DT(format->mipi_dt) | RKISP1_CIF_MIPI_DATA_SEL_VC(0)); /* Clear MIPI interrupts */ @@ -151,7 +135,8 @@ static void rkisp1_csi_disable(struct rkisp1_csi *csi) } static int rkisp1_csi_start(struct rkisp1_csi *csi, - const struct rkisp1_sensor_async *sensor) + const struct rkisp1_sensor_async *sensor, + const struct rkisp1_mbus_info *format) { struct rkisp1_device *rkisp1 = csi->rkisp1; union phy_configure_opts opts; @@ -159,7 +144,7 @@ static int rkisp1_csi_start(struct rkisp1_csi *csi, s64 pixel_clock; int ret; - ret = rkisp1_csi_config(csi, sensor); + ret = rkisp1_csi_config(csi, sensor, format); if (ret) return ret; @@ -169,7 +154,7 @@ static int rkisp1_csi_start(struct rkisp1_csi *csi, return -EINVAL; } - phy_mipi_dphy_get_default_config(pixel_clock, csi->sink_fmt->bus_width, + phy_mipi_dphy_get_default_config(pixel_clock, format->bus_width, sensor->lanes, cfg); phy_set_mode(csi->dphy, PHY_MODE_MIPI_DPHY); phy_configure(csi->dphy, &opts); @@ -248,7 +233,6 @@ static int rkisp1_csi_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { - struct rkisp1_csi *csi = to_rkisp1_csi(sd); unsigned int i; int pos = 0; @@ -258,15 +242,10 @@ static int rkisp1_csi_enum_mbus_code(struct v4l2_subdev *sd, if (code->index) return -EINVAL; - mutex_lock(&csi->lock); - - sink_fmt = rkisp1_csi_get_pad_fmt(csi, sd_state, - RKISP1_CSI_PAD_SINK, - code->which); + sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, + RKISP1_CSI_PAD_SINK); code->code = sink_fmt->code; - mutex_unlock(&csi->lock); - return 0; } @@ -296,9 +275,9 @@ static int rkisp1_csi_init_config(struct v4l2_subdev *sd, { struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; - sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, + sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_CSI_PAD_SINK); - src_fmt = v4l2_subdev_get_try_format(sd, sd_state, + src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_CSI_PAD_SRC); sink_fmt->width = RKISP1_DEFAULT_WIDTH; @@ -311,36 +290,18 @@ static int rkisp1_csi_init_config(struct v4l2_subdev *sd, return 0; } -static int rkisp1_csi_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct rkisp1_csi *csi = to_rkisp1_csi(sd); - - mutex_lock(&csi->lock); - fmt->format = *rkisp1_csi_get_pad_fmt(csi, sd_state, fmt->pad, - fmt->which); - mutex_unlock(&csi->lock); - - return 0; -} - static int rkisp1_csi_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { - struct rkisp1_csi *csi = to_rkisp1_csi(sd); const struct rkisp1_mbus_info *mbus_info; struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; /* The format on the source pad always matches the sink pad. */ if (fmt->pad == RKISP1_CSI_PAD_SRC) - return rkisp1_csi_get_fmt(sd, sd_state, fmt); + return v4l2_subdev_get_fmt(sd, sd_state, fmt); - mutex_lock(&csi->lock); - - sink_fmt = rkisp1_csi_get_pad_fmt(csi, sd_state, RKISP1_CSI_PAD_SINK, - fmt->which); + sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_CSI_PAD_SINK); sink_fmt->code = fmt->format.code; @@ -359,16 +320,10 @@ static int rkisp1_csi_set_fmt(struct v4l2_subdev *sd, fmt->format = *sink_fmt; - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) - csi->sink_fmt = mbus_info; - /* Propagate the format to the source pad. */ - src_fmt = rkisp1_csi_get_pad_fmt(csi, sd_state, RKISP1_CSI_PAD_SRC, - fmt->which); + src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_CSI_PAD_SRC); *src_fmt = *sink_fmt; - mutex_unlock(&csi->lock); - return 0; } @@ -380,8 +335,11 @@ static int rkisp1_csi_s_stream(struct v4l2_subdev *sd, int enable) { struct rkisp1_csi *csi = to_rkisp1_csi(sd); struct rkisp1_device *rkisp1 = csi->rkisp1; + const struct v4l2_mbus_framefmt *sink_fmt; + const struct rkisp1_mbus_info *format; struct rkisp1_sensor_async *source_asd; struct v4l2_async_connection *asc; + struct v4l2_subdev_state *sd_state; struct media_pad *source_pad; struct v4l2_subdev *source; int ret; @@ -415,9 +373,12 @@ static int rkisp1_csi_s_stream(struct v4l2_subdev *sd, int enable) if (source_asd->mbus_type != V4L2_MBUS_CSI2_DPHY) return -EINVAL; - mutex_lock(&csi->lock); - ret = rkisp1_csi_start(csi, source_asd); - mutex_unlock(&csi->lock); + sd_state = v4l2_subdev_lock_and_get_active_state(sd); + sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_CSI_PAD_SINK); + format = rkisp1_mbus_info_get_by_code(sink_fmt->code); + v4l2_subdev_unlock_state(sd_state); + + ret = rkisp1_csi_start(csi, source_asd, format); if (ret) return ret; @@ -447,7 +408,7 @@ static const struct v4l2_subdev_video_ops rkisp1_csi_video_ops = { static const struct v4l2_subdev_pad_ops rkisp1_csi_pad_ops = { .enum_mbus_code = rkisp1_csi_enum_mbus_code, .init_cfg = rkisp1_csi_init_config, - .get_fmt = rkisp1_csi_get_fmt, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = rkisp1_csi_set_fmt, }; @@ -459,13 +420,11 @@ static const struct v4l2_subdev_ops rkisp1_csi_ops = { int rkisp1_csi_register(struct rkisp1_device *rkisp1) { struct rkisp1_csi *csi = &rkisp1->csi; - struct v4l2_subdev_state state = {}; struct media_pad *pads; struct v4l2_subdev *sd; int ret; csi->rkisp1 = rkisp1; - mutex_init(&csi->lock); sd = &csi->sd; v4l2_subdev_init(sd, &rkisp1_csi_ops); @@ -481,26 +440,26 @@ int rkisp1_csi_register(struct rkisp1_device *rkisp1) pads[RKISP1_CSI_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT; - csi->sink_fmt = rkisp1_mbus_info_get_by_code(RKISP1_CSI_DEF_FMT); - ret = media_entity_pads_init(&sd->entity, RKISP1_CSI_PAD_NUM, pads); if (ret) - goto error; + goto err_entity_cleanup; - state.pads = csi->pad_cfg; - rkisp1_csi_init_config(sd, &state); + ret = v4l2_subdev_init_finalize(sd); + if (ret) + goto err_entity_cleanup; ret = v4l2_device_register_subdev(&csi->rkisp1->v4l2_dev, sd); if (ret) { dev_err(sd->dev, "Failed to register csi receiver subdev\n"); - goto error; + goto err_subdev_cleanup; } return 0; -error: +err_subdev_cleanup: + v4l2_subdev_cleanup(sd); +err_entity_cleanup: media_entity_cleanup(&sd->entity); - mutex_destroy(&csi->lock); csi->rkisp1 = NULL; return ret; } @@ -513,8 +472,8 @@ void rkisp1_csi_unregister(struct rkisp1_device *rkisp1) return; v4l2_device_unregister_subdev(&csi->sd); + v4l2_subdev_cleanup(&csi->sd); media_entity_cleanup(&csi->sd.entity); - mutex_destroy(&csi->lock); } int rkisp1_csi_init(struct rkisp1_device *rkisp1) -- GitLab From cde4e5157af3fdb3d8131bc39309e6dae6a7555a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 23 Sep 2023 23:36:03 +0300 Subject: [PATCH 0553/1451] media: rkisp1: Convert hex constants to lowercase Hex constants in the media subsystem are typically in lowercase. The rkisp1 driver mostly follows that convention already, except in the register definitions. Convert all hex constants to lowercase for consistency. Signed-off-by: Laurent Pinchart Reviewed-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../platform/rockchip/rkisp1/rkisp1-params.c | 2 +- .../platform/rockchip/rkisp1/rkisp1-regs.h | 620 +++++++++--------- 2 files changed, 311 insertions(+), 311 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index 3482f7d707b75..8e3dc4966b947 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -812,7 +812,7 @@ static void rkisp1_hst_config_v10(struct rkisp1_params *params, weight[2], weight[3])); rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_WEIGHT_44_V10, - weight[0] & 0x1F); + weight[0] & 0x1f); } static void rkisp1_hst_config_v12(struct rkisp1_params *params, diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h index 421cc73355dbf..350f452e676f2 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h @@ -273,13 +273,13 @@ #define RKISP1_CIF_C_PROC_YOUT_FULL BIT(1) #define RKISP1_CIF_C_PROC_YIN_FULL BIT(2) #define RKISP1_CIF_C_PROC_COUT_FULL BIT(3) -#define RKISP1_CIF_C_PROC_CTRL_RESERVED 0xFFFFFFFE -#define RKISP1_CIF_C_PROC_CONTRAST_RESERVED 0xFFFFFF00 -#define RKISP1_CIF_C_PROC_BRIGHTNESS_RESERVED 0xFFFFFF00 -#define RKISP1_CIF_C_PROC_HUE_RESERVED 0xFFFFFF00 -#define RKISP1_CIF_C_PROC_SATURATION_RESERVED 0xFFFFFF00 -#define RKISP1_CIF_C_PROC_MACC_RESERVED 0xE000E000 -#define RKISP1_CIF_C_PROC_TONE_RESERVED 0xF000 +#define RKISP1_CIF_C_PROC_CTRL_RESERVED 0xfffffffe +#define RKISP1_CIF_C_PROC_CONTRAST_RESERVED 0xffffff00 +#define RKISP1_CIF_C_PROC_BRIGHTNESS_RESERVED 0xffffff00 +#define RKISP1_CIF_C_PROC_HUE_RESERVED 0xffffff00 +#define RKISP1_CIF_C_PROC_SATURATION_RESERVED 0xffffff00 +#define RKISP1_CIF_C_PROC_MACC_RESERVED 0xe000e000 +#define RKISP1_CIF_C_PROC_TONE_RESERVED 0xf000 /* DUAL_CROP_CTRL */ #define RKISP1_CIF_DUAL_CROP_MP_MODE_BYPASS (0 << 0) #define RKISP1_CIF_DUAL_CROP_MP_MODE_YUV (1 << 0) @@ -310,7 +310,7 @@ #define RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS_SHIFT 4 #define RKISP1_CIF_IMG_EFF_CTRL_MODE_SKETCH_SHIFT 5 #define RKISP1_CIF_IMG_EFF_CTRL_MODE_SHARPEN_SHIFT 6 -#define RKISP1_CIF_IMG_EFF_CTRL_MODE_MASK 0xE +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_MASK 0xe /* IMG_EFF_COLOR_SEL */ #define RKISP1_CIF_IMG_EFF_COLOR_RGB 0 @@ -324,7 +324,7 @@ /* MIPI_CTRL */ #define RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA BIT(0) -#define RKISP1_CIF_MIPI_CTRL_SHUTDOWNLANES(a) (((a) & 0xF) << 8) +#define RKISP1_CIF_MIPI_CTRL_SHUTDOWNLANES(a) (((a) & 0xf) << 8) #define RKISP1_CIF_MIPI_CTRL_NUM_LANES(a) (((a) & 0x3) << 12) #define RKISP1_CIF_MIPI_CTRL_ERR_SOT_HS_SKIP BIT(16) #define RKISP1_CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP BIT(17) @@ -332,14 +332,14 @@ /* MIPI_DATA_SEL */ #define RKISP1_CIF_MIPI_DATA_SEL_VC(a) (((a) & 0x3) << 6) -#define RKISP1_CIF_MIPI_DATA_SEL_DT(a) (((a) & 0x3F) << 0) +#define RKISP1_CIF_MIPI_DATA_SEL_DT(a) (((a) & 0x3f) << 0) /* MIPI_IMSC, MIPI_RIS, MIPI_MIS, MIPI_ICR, MIPI_ISR */ -#define RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(a) (((a) & 0xF) << 0) -#define RKISP1_CIF_MIPI_ERR_SOT(a) (((a) & 0xF) << 4) -#define RKISP1_CIF_MIPI_ERR_SOT_SYNC(a) (((a) & 0xF) << 8) -#define RKISP1_CIF_MIPI_ERR_EOT_SYNC(a) (((a) & 0xF) << 12) -#define RKISP1_CIF_MIPI_ERR_CTRL(a) (((a) & 0xF) << 16) +#define RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(a) (((a) & 0xf) << 0) +#define RKISP1_CIF_MIPI_ERR_SOT(a) (((a) & 0xf) << 4) +#define RKISP1_CIF_MIPI_ERR_SOT_SYNC(a) (((a) & 0xf) << 8) +#define RKISP1_CIF_MIPI_ERR_EOT_SYNC(a) (((a) & 0xf) << 12) +#define RKISP1_CIF_MIPI_ERR_CTRL(a) (((a) & 0xf) << 16) #define RKISP1_CIF_MIPI_ERR_PROTOCOL BIT(20) #define RKISP1_CIF_MIPI_ERR_ECC1 BIT(21) #define RKISP1_CIF_MIPI_ERR_ECC2 BIT(22) @@ -371,28 +371,28 @@ #define RKISP1_CIF_ISP_HIST_PROP_MODE_BLUE_V10 (4 << 0) #define RKISP1_CIF_ISP_HIST_PROP_MODE_LUM_V10 (5 << 0) #define RKISP1_CIF_ISP_HIST_PROP_MODE_MASK_V10 0x7 -#define RKISP1_CIF_ISP_HIST_PREDIV_SET_V10(x) (((x) & 0x7F) << 3) +#define RKISP1_CIF_ISP_HIST_PREDIV_SET_V10(x) (((x) & 0x7f) << 3) #define RKISP1_CIF_ISP_HIST_WEIGHT_SET_V10(v0, v1, v2, v3) \ - (((v0) & 0x1F) | (((v1) & 0x1F) << 8) |\ - (((v2) & 0x1F) << 16) | \ - (((v3) & 0x1F) << 24)) - -#define RKISP1_CIF_ISP_HIST_WINDOW_OFFSET_RESERVED_V10 0xFFFFF000 -#define RKISP1_CIF_ISP_HIST_WINDOW_SIZE_RESERVED_V10 0xFFFFF800 -#define RKISP1_CIF_ISP_HIST_WEIGHT_RESERVED_V10 0xE0E0E0E0 -#define RKISP1_CIF_ISP_MAX_HIST_PREDIVIDER_V10 0x0000007F + (((v0) & 0x1f) | (((v1) & 0x1f) << 8) |\ + (((v2) & 0x1f) << 16) | \ + (((v3) & 0x1f) << 24)) + +#define RKISP1_CIF_ISP_HIST_WINDOW_OFFSET_RESERVED_V10 0xfffff000 +#define RKISP1_CIF_ISP_HIST_WINDOW_SIZE_RESERVED_V10 0xfffff800 +#define RKISP1_CIF_ISP_HIST_WEIGHT_RESERVED_V10 0xe0e0e0e0 +#define RKISP1_CIF_ISP_MAX_HIST_PREDIVIDER_V10 0x0000007f #define RKISP1_CIF_ISP_HIST_ROW_NUM_V10 5 #define RKISP1_CIF_ISP_HIST_COLUMN_NUM_V10 5 -#define RKISP1_CIF_ISP_HIST_GET_BIN_V10(x) ((x) & 0x000FFFFF) +#define RKISP1_CIF_ISP_HIST_GET_BIN_V10(x) ((x) & 0x000fffff) /* ISP HISTOGRAM CALCULATION : CIF_ISP_HIST */ #define RKISP1_CIF_ISP_HIST_CTRL_EN_SET_V12(x) (((x) & 0x01) << 0) #define RKISP1_CIF_ISP_HIST_CTRL_EN_MASK_V12 RKISP1_CIF_ISP_HIST_CTRL_EN_SET_V12(0x01) -#define RKISP1_CIF_ISP_HIST_CTRL_STEPSIZE_SET_V12(x) (((x) & 0x7F) << 1) +#define RKISP1_CIF_ISP_HIST_CTRL_STEPSIZE_SET_V12(x) (((x) & 0x7f) << 1) #define RKISP1_CIF_ISP_HIST_CTRL_MODE_SET_V12(x) (((x) & 0x07) << 8) #define RKISP1_CIF_ISP_HIST_CTRL_MODE_MASK_V12 RKISP1_CIF_ISP_HIST_CTRL_MODE_SET_V12(0x07) #define RKISP1_CIF_ISP_HIST_CTRL_AUTOSTOP_SET_V12(x) (((x) & 0x01) << 11) -#define RKISP1_CIF_ISP_HIST_CTRL_WATERLINE_SET_V12(x) (((x) & 0xFFF) << 12) +#define RKISP1_CIF_ISP_HIST_CTRL_WATERLINE_SET_V12(x) (((x) & 0xfff) << 12) #define RKISP1_CIF_ISP_HIST_CTRL_DATASEL_SET_V12(x) (((x) & 0x07) << 24) #define RKISP1_CIF_ISP_HIST_CTRL_INTRSEL_SET_V12(x) (((x) & 0x01) << 27) #define RKISP1_CIF_ISP_HIST_CTRL_WNDNUM_SET_V12(x) (((x) & 0x03) << 28) @@ -403,19 +403,19 @@ (RKISP1_CIF_ISP_HIST_ROW_NUM_V12 * RKISP1_CIF_ISP_HIST_COLUMN_NUM_V12) #define RKISP1_CIF_ISP_HIST_WEIGHT_SET_V12(v0, v1, v2, v3) \ - (((v0) & 0x3F) | (((v1) & 0x3F) << 8) |\ - (((v2) & 0x3F) << 16) |\ - (((v3) & 0x3F) << 24)) + (((v0) & 0x3f) | (((v1) & 0x3f) << 8) |\ + (((v2) & 0x3f) << 16) |\ + (((v3) & 0x3f) << 24)) #define RKISP1_CIF_ISP_HIST_OFFS_SET_V12(v0, v1) \ - (((v0) & 0x1FFF) | (((v1) & 0x1FFF) << 16)) + (((v0) & 0x1fff) | (((v1) & 0x1fff) << 16)) #define RKISP1_CIF_ISP_HIST_SIZE_SET_V12(v0, v1) \ - (((v0) & 0x7FF) | (((v1) & 0x7FF) << 16)) + (((v0) & 0x7ff) | (((v1) & 0x7ff) << 16)) #define RKISP1_CIF_ISP_HIST_GET_BIN0_V12(x) \ - ((x) & 0xFFFF) + ((x) & 0xffff) #define RKISP1_CIF_ISP_HIST_GET_BIN1_V12(x) \ - (((x) >> 16) & 0xFFFF) + (((x) >> 16) & 0xffff) /* AUTO FOCUS MEASUREMENT: ISP_AFM_CTRL */ #define RKISP1_ISP_AFM_CTRL_ENABLE BIT(0) @@ -437,11 +437,11 @@ #define RKISP1_CIFFLASH_CONFIG_VSYNC_POS BIT(1) #define RKISP1_CIFFLASH_CONFIG_PRELIGHT_LOW BIT(2) #define RKISP1_CIFFLASH_CONFIG_SRC_FL_TRIG BIT(3) -#define RKISP1_CIFFLASH_CONFIG_DELAY(a) (((a) & 0xF) << 4) +#define RKISP1_CIFFLASH_CONFIG_DELAY(a) (((a) & 0xf) << 4) /* Demosaic: ISP_DEMOSAIC */ #define RKISP1_CIF_ISP_DEMOSAIC_BYPASS BIT(10) -#define RKISP1_CIF_ISP_DEMOSAIC_TH(x) ((x) & 0xFF) +#define RKISP1_CIF_ISP_DEMOSAIC_TH(x) ((x) & 0xff) /* ISP_FLAGS_SHD */ #define RKISP1_CIF_ISP_FLAGS_SHD_ISP_ENABLE_SHD BIT(0) @@ -458,39 +458,39 @@ #define RKISP1_CIF_ISP_AWB_YMAX_READ(x) (((x) >> 2) & 1) #define RKISP1_CIF_ISP_AWB_MODE_RGB_EN ((1 << 31) | (0x2 << 0)) #define RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN ((0 << 31) | (0x2 << 0)) -#define RKISP1_CIF_ISP_AWB_MODE_MASK_NONE 0xFFFFFFFC +#define RKISP1_CIF_ISP_AWB_MODE_MASK_NONE 0xfffffffc #define RKISP1_CIF_ISP_AWB_MODE_READ(x) ((x) & 3) #define RKISP1_CIF_ISP_AWB_SET_FRAMES_V12(x) (((x) & 0x07) << 28) #define RKISP1_CIF_ISP_AWB_SET_FRAMES_MASK_V12 RKISP1_CIF_ISP_AWB_SET_FRAMES_V12(0x07) /* ISP_AWB_GAIN_RB, ISP_AWB_GAIN_G */ -#define RKISP1_CIF_ISP_AWB_GAIN_R_SET(x) (((x) & 0x3FF) << 16) -#define RKISP1_CIF_ISP_AWB_GAIN_R_READ(x) (((x) >> 16) & 0x3FF) -#define RKISP1_CIF_ISP_AWB_GAIN_B_SET(x) ((x) & 0x3FFF) -#define RKISP1_CIF_ISP_AWB_GAIN_B_READ(x) ((x) & 0x3FFF) +#define RKISP1_CIF_ISP_AWB_GAIN_R_SET(x) (((x) & 0x3ff) << 16) +#define RKISP1_CIF_ISP_AWB_GAIN_R_READ(x) (((x) >> 16) & 0x3ff) +#define RKISP1_CIF_ISP_AWB_GAIN_B_SET(x) ((x) & 0x3fff) +#define RKISP1_CIF_ISP_AWB_GAIN_B_READ(x) ((x) & 0x3fff) /* ISP_AWB_REF */ -#define RKISP1_CIF_ISP_AWB_REF_CR_SET(x) (((x) & 0xFF) << 8) -#define RKISP1_CIF_ISP_AWB_REF_CR_READ(x) (((x) >> 8) & 0xFF) -#define RKISP1_CIF_ISP_AWB_REF_CB_READ(x) ((x) & 0xFF) +#define RKISP1_CIF_ISP_AWB_REF_CR_SET(x) (((x) & 0xff) << 8) +#define RKISP1_CIF_ISP_AWB_REF_CR_READ(x) (((x) >> 8) & 0xff) +#define RKISP1_CIF_ISP_AWB_REF_CB_READ(x) ((x) & 0xff) /* ISP_AWB_THRESH */ -#define RKISP1_CIF_ISP_AWB_MAX_CS_SET(x) (((x) & 0xFF) << 8) -#define RKISP1_CIF_ISP_AWB_MAX_CS_READ(x) (((x) >> 8) & 0xFF) -#define RKISP1_CIF_ISP_AWB_MIN_C_READ(x) ((x) & 0xFF) -#define RKISP1_CIF_ISP_AWB_MIN_Y_SET(x) (((x) & 0xFF) << 16) -#define RKISP1_CIF_ISP_AWB_MIN_Y_READ(x) (((x) >> 16) & 0xFF) -#define RKISP1_CIF_ISP_AWB_MAX_Y_SET(x) (((x) & 0xFF) << 24) -#define RKISP1_CIF_ISP_AWB_MAX_Y_READ(x) (((x) >> 24) & 0xFF) +#define RKISP1_CIF_ISP_AWB_MAX_CS_SET(x) (((x) & 0xff) << 8) +#define RKISP1_CIF_ISP_AWB_MAX_CS_READ(x) (((x) >> 8) & 0xff) +#define RKISP1_CIF_ISP_AWB_MIN_C_READ(x) ((x) & 0xff) +#define RKISP1_CIF_ISP_AWB_MIN_Y_SET(x) (((x) & 0xff) << 16) +#define RKISP1_CIF_ISP_AWB_MIN_Y_READ(x) (((x) >> 16) & 0xff) +#define RKISP1_CIF_ISP_AWB_MAX_Y_SET(x) (((x) & 0xff) << 24) +#define RKISP1_CIF_ISP_AWB_MAX_Y_READ(x) (((x) >> 24) & 0xff) /* ISP_AWB_MEAN */ -#define RKISP1_CIF_ISP_AWB_GET_MEAN_CR_R(x) ((x) & 0xFF) -#define RKISP1_CIF_ISP_AWB_GET_MEAN_CB_B(x) (((x) >> 8) & 0xFF) -#define RKISP1_CIF_ISP_AWB_GET_MEAN_Y_G(x) (((x) >> 16) & 0xFF) +#define RKISP1_CIF_ISP_AWB_GET_MEAN_CR_R(x) ((x) & 0xff) +#define RKISP1_CIF_ISP_AWB_GET_MEAN_CB_B(x) (((x) >> 8) & 0xff) +#define RKISP1_CIF_ISP_AWB_GET_MEAN_Y_G(x) (((x) >> 16) & 0xff) /* ISP_AWB_WHITE_CNT */ -#define RKISP1_CIF_ISP_AWB_GET_PIXEL_CNT(x) ((x) & 0x3FFFFFF) +#define RKISP1_CIF_ISP_AWB_GET_PIXEL_CNT(x) ((x) & 0x3ffffff) -#define RKISP1_CIF_ISP_AWB_GAINS_MAX_VAL 0x000003FF -#define RKISP1_CIF_ISP_AWB_WINDOW_OFFSET_MAX 0x00000FFF -#define RKISP1_CIF_ISP_AWB_WINDOW_MAX_SIZE 0x00001FFF -#define RKISP1_CIF_ISP_AWB_CBCR_MAX_REF 0x000000FF -#define RKISP1_CIF_ISP_AWB_THRES_MAX_YC 0x000000FF +#define RKISP1_CIF_ISP_AWB_GAINS_MAX_VAL 0x000003ff +#define RKISP1_CIF_ISP_AWB_WINDOW_OFFSET_MAX 0x00000fff +#define RKISP1_CIF_ISP_AWB_WINDOW_MAX_SIZE 0x00001fff +#define RKISP1_CIF_ISP_AWB_CBCR_MAX_REF 0x000000ff +#define RKISP1_CIF_ISP_AWB_THRES_MAX_YC 0x000000ff /* AE */ /* ISP_EXP_CTRL */ @@ -504,24 +504,24 @@ #define RKISP1_CIF_ISP_EXP_CTRL_MEASMODE_1 BIT(31) /* ISP_EXP_H_SIZE */ -#define RKISP1_CIF_ISP_EXP_H_SIZE_SET_V10(x) ((x) & 0x7FF) -#define RKISP1_CIF_ISP_EXP_HEIGHT_MASK_V10 0x000007FF -#define RKISP1_CIF_ISP_EXP_H_SIZE_SET_V12(x) ((x) & 0x7FF) -#define RKISP1_CIF_ISP_EXP_HEIGHT_MASK_V12 0x000007FF +#define RKISP1_CIF_ISP_EXP_H_SIZE_SET_V10(x) ((x) & 0x7ff) +#define RKISP1_CIF_ISP_EXP_HEIGHT_MASK_V10 0x000007ff +#define RKISP1_CIF_ISP_EXP_H_SIZE_SET_V12(x) ((x) & 0x7ff) +#define RKISP1_CIF_ISP_EXP_HEIGHT_MASK_V12 0x000007ff /* ISP_EXP_V_SIZE : vertical size must be a multiple of 2). */ -#define RKISP1_CIF_ISP_EXP_V_SIZE_SET_V10(x) ((x) & 0x7FE) -#define RKISP1_CIF_ISP_EXP_V_SIZE_SET_V12(x) (((x) & 0x7FE) << 16) +#define RKISP1_CIF_ISP_EXP_V_SIZE_SET_V10(x) ((x) & 0x7fe) +#define RKISP1_CIF_ISP_EXP_V_SIZE_SET_V12(x) (((x) & 0x7fe) << 16) /* ISP_EXP_H_OFFSET */ -#define RKISP1_CIF_ISP_EXP_H_OFFSET_SET_V10(x) ((x) & 0x1FFF) +#define RKISP1_CIF_ISP_EXP_H_OFFSET_SET_V10(x) ((x) & 0x1fff) #define RKISP1_CIF_ISP_EXP_MAX_HOFFS_V10 2424 -#define RKISP1_CIF_ISP_EXP_H_OFFSET_SET_V12(x) ((x) & 0x1FFF) -#define RKISP1_CIF_ISP_EXP_MAX_HOFFS_V12 0x1FFF +#define RKISP1_CIF_ISP_EXP_H_OFFSET_SET_V12(x) ((x) & 0x1fff) +#define RKISP1_CIF_ISP_EXP_MAX_HOFFS_V12 0x1fff /* ISP_EXP_V_OFFSET */ -#define RKISP1_CIF_ISP_EXP_V_OFFSET_SET_V10(x) ((x) & 0x1FFF) +#define RKISP1_CIF_ISP_EXP_V_OFFSET_SET_V10(x) ((x) & 0x1fff) #define RKISP1_CIF_ISP_EXP_MAX_VOFFS_V10 1806 -#define RKISP1_CIF_ISP_EXP_V_OFFSET_SET_V12(x) (((x) & 0x1FFF) << 16) -#define RKISP1_CIF_ISP_EXP_MAX_VOFFS_V12 0x1FFF +#define RKISP1_CIF_ISP_EXP_V_OFFSET_SET_V12(x) (((x) & 0x1fff) << 16) +#define RKISP1_CIF_ISP_EXP_MAX_VOFFS_V12 0x1fff #define RKISP1_CIF_ISP_EXP_ROW_NUM_V10 5 #define RKISP1_CIF_ISP_EXP_COLUMN_NUM_V10 5 @@ -545,10 +545,10 @@ #define RKISP1_CIF_ISP_EXP_NUM_LUMA_REGS_V12 \ (RKISP1_CIF_ISP_EXP_ROW_NUM_V12 * RKISP1_CIF_ISP_EXP_COLUMN_NUM_V12) -#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_HSIZE_V12 0x7FF -#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_HSIZE_V12 0xE -#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_VSIZE_V12 0x7FE -#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE_V12 0xE +#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_HSIZE_V12 0x7ff +#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_HSIZE_V12 0xe +#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_VSIZE_V12 0x7fe +#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE_V12 0xe #define RKISP1_CIF_ISP_EXP_MAX_HSIZE_V12 \ (RKISP1_CIF_ISP_EXP_BLOCK_MAX_HSIZE_V12 * RKISP1_CIF_ISP_EXP_COLUMN_NUM_V12 + 1) #define RKISP1_CIF_ISP_EXP_MIN_HSIZE_V12 \ @@ -558,26 +558,26 @@ #define RKISP1_CIF_ISP_EXP_MIN_VSIZE_V12 \ (RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE_V12 * RKISP1_CIF_ISP_EXP_ROW_NUM_V12 + 1) -#define RKISP1_CIF_ISP_EXP_GET_MEAN_xy0_V12(x) ((x) & 0xFF) -#define RKISP1_CIF_ISP_EXP_GET_MEAN_xy1_V12(x) (((x) >> 8) & 0xFF) -#define RKISP1_CIF_ISP_EXP_GET_MEAN_xy2_V12(x) (((x) >> 16) & 0xFF) -#define RKISP1_CIF_ISP_EXP_GET_MEAN_xy3_V12(x) (((x) >> 24) & 0xFF) +#define RKISP1_CIF_ISP_EXP_GET_MEAN_xy0_V12(x) ((x) & 0xff) +#define RKISP1_CIF_ISP_EXP_GET_MEAN_xy1_V12(x) (((x) >> 8) & 0xff) +#define RKISP1_CIF_ISP_EXP_GET_MEAN_xy2_V12(x) (((x) >> 16) & 0xff) +#define RKISP1_CIF_ISP_EXP_GET_MEAN_xy3_V12(x) (((x) >> 24) & 0xff) /* LSC: ISP_LSC_CTRL */ #define RKISP1_CIF_ISP_LSC_CTRL_ENA BIT(0) -#define RKISP1_CIF_ISP_LSC_SECT_SIZE_RESERVED 0xFC00FC00 -#define RKISP1_CIF_ISP_LSC_GRAD_RESERVED_V10 0xF000F000 -#define RKISP1_CIF_ISP_LSC_SAMPLE_RESERVED_V10 0xF000F000 -#define RKISP1_CIF_ISP_LSC_GRAD_RESERVED_V12 0xE000E000 -#define RKISP1_CIF_ISP_LSC_SAMPLE_RESERVED_V12 0xE000E000 +#define RKISP1_CIF_ISP_LSC_SECT_SIZE_RESERVED 0xfc00fc00 +#define RKISP1_CIF_ISP_LSC_GRAD_RESERVED_V10 0xf000f000 +#define RKISP1_CIF_ISP_LSC_SAMPLE_RESERVED_V10 0xf000f000 +#define RKISP1_CIF_ISP_LSC_GRAD_RESERVED_V12 0xe000e000 +#define RKISP1_CIF_ISP_LSC_SAMPLE_RESERVED_V12 0xe000e000 #define RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(v0, v1) \ - (((v0) & 0xFFF) | (((v1) & 0xFFF) << 12)) + (((v0) & 0xfff) | (((v1) & 0xfff) << 12)) #define RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(v0, v1) \ - (((v0) & 0x1FFF) | (((v1) & 0x1FFF) << 13)) + (((v0) & 0x1fff) | (((v1) & 0x1fff) << 13)) #define RKISP1_CIF_ISP_LSC_SECT_SIZE(v0, v1) \ - (((v0) & 0xFFF) | (((v1) & 0xFFF) << 16)) + (((v0) & 0xfff) | (((v1) & 0xfff) << 16)) #define RKISP1_CIF_ISP_LSC_SECT_GRAD(v0, v1) \ - (((v0) & 0xFFF) | (((v1) & 0xFFF) << 16)) + (((v0) & 0xfff) | (((v1) & 0xfff) << 16)) /* LSC: ISP_LSC_TABLE_SEL */ #define RKISP1_CIF_ISP_LSC_TABLE_0 0 @@ -601,19 +601,19 @@ #define RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(x) (((x) & 0x3) << 4) #define RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(x) (((x) & 0x3) << 6) #define RKISP1_CIF_ISP_FLT_CHROMA_MODE_MAX 3 -#define RKISP1_CIF_ISP_FLT_GREEN_STAGE1(x) (((x) & 0xF) << 8) +#define RKISP1_CIF_ISP_FLT_GREEN_STAGE1(x) (((x) & 0xf) << 8) #define RKISP1_CIF_ISP_FLT_GREEN_STAGE1_MAX 8 -#define RKISP1_CIF_ISP_FLT_THREAD_RESERVED 0xFFFFFC00 -#define RKISP1_CIF_ISP_FLT_FAC_RESERVED 0xFFFFFFC0 -#define RKISP1_CIF_ISP_FLT_LUM_WEIGHT_RESERVED 0xFFF80000 +#define RKISP1_CIF_ISP_FLT_THREAD_RESERVED 0xfffffc00 +#define RKISP1_CIF_ISP_FLT_FAC_RESERVED 0xffffffc0 +#define RKISP1_CIF_ISP_FLT_LUM_WEIGHT_RESERVED 0xfff80000 -#define RKISP1_CIF_ISP_CTK_COEFF_RESERVED 0xFFFFF800 -#define RKISP1_CIF_ISP_XTALK_OFFSET_RESERVED 0xFFFFF000 +#define RKISP1_CIF_ISP_CTK_COEFF_RESERVED 0xfffff800 +#define RKISP1_CIF_ISP_XTALK_OFFSET_RESERVED 0xfffff000 /* GOC */ #define RKISP1_CIF_ISP_GAMMA_OUT_MODE_EQU BIT(0) #define RKISP1_CIF_ISP_GOC_MODE_MAX 1 -#define RKISP1_CIF_ISP_GOC_RESERVED 0xFFFFF800 +#define RKISP1_CIF_ISP_GOC_RESERVED 0xfffff800 /* ISP_CTRL BIT 11*/ #define RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA_READ(x) (((x) >> 11) & 1) @@ -643,22 +643,22 @@ #define RKISP1_CIFISP_DEGAMMA_X_RESERVED \ ((1 << 31) | (1 << 27) | (1 << 23) | (1 << 19) |\ (1 << 15) | (1 << 11) | (1 << 7) | (1 << 3)) -#define RKISP1_CIFISP_DEGAMMA_Y_RESERVED 0xFFFFF000 +#define RKISP1_CIFISP_DEGAMMA_Y_RESERVED 0xfffff000 /* GAMMA-OUT */ #define RKISP1_CIF_ISP_GAMMA_VALUE_V12(x, y) \ - (((x) & 0xFFF) << 16 | ((y) & 0xFFF) << 0) + (((x) & 0xfff) << 16 | ((y) & 0xfff) << 0) /* AFM */ #define RKISP1_CIF_ISP_AFM_ENA BIT(0) -#define RKISP1_CIF_ISP_AFM_THRES_RESERVED 0xFFFF0000 -#define RKISP1_CIF_ISP_AFM_VAR_SHIFT_RESERVED 0xFFF8FFF8 -#define RKISP1_CIF_ISP_AFM_WINDOW_X_RESERVED 0xE000 -#define RKISP1_CIF_ISP_AFM_WINDOW_Y_RESERVED 0xF000 +#define RKISP1_CIF_ISP_AFM_THRES_RESERVED 0xffff0000 +#define RKISP1_CIF_ISP_AFM_VAR_SHIFT_RESERVED 0xfff8fff8 +#define RKISP1_CIF_ISP_AFM_WINDOW_X_RESERVED 0xe000 +#define RKISP1_CIF_ISP_AFM_WINDOW_Y_RESERVED 0xf000 #define RKISP1_CIF_ISP_AFM_WINDOW_X_MIN 0x5 #define RKISP1_CIF_ISP_AFM_WINDOW_Y_MIN 0x2 -#define RKISP1_CIF_ISP_AFM_WINDOW_X(x) (((x) & 0x1FFF) << 16) -#define RKISP1_CIF_ISP_AFM_WINDOW_Y(x) ((x) & 0x1FFF) +#define RKISP1_CIF_ISP_AFM_WINDOW_X(x) (((x) & 0x1fff) << 16) +#define RKISP1_CIF_ISP_AFM_WINDOW_Y(x) ((x) & 0x1fff) #define RKISP1_CIF_ISP_AFM_SET_SHIFT_a_V12(x, y) (((x) & 0x7) << 16 | ((y) & 0x7) << 0) #define RKISP1_CIF_ISP_AFM_SET_SHIFT_b_V12(x, y) (((x) & 0x7) << 20 | ((y) & 0x7) << 4) #define RKISP1_CIF_ISP_AFM_SET_SHIFT_c_V12(x, y) (((x) & 0x7) << 24 | ((y) & 0x7) << 8) @@ -676,9 +676,9 @@ #define RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP BIT(7) #define RKISP1_CIF_ISP_DPF_MODE_LSC_GAIN_COMP BIT(8) #define RKISP1_CIF_ISP_DPF_MODE_USE_NF_GAIN BIT(9) -#define RKISP1_CIF_ISP_DPF_NF_GAIN_RESERVED 0xFFFFF000 -#define RKISP1_CIF_ISP_DPF_SPATIAL_COEFF_MAX 0x1F -#define RKISP1_CIF_ISP_DPF_NLL_COEFF_N_MAX 0x3FF +#define RKISP1_CIF_ISP_DPF_NF_GAIN_RESERVED 0xfffff000 +#define RKISP1_CIF_ISP_DPF_SPATIAL_COEFF_MAX 0x1f +#define RKISP1_CIF_ISP_DPF_NLL_COEFF_N_MAX 0x3ff /* =================================================================== */ /* CIF Registers */ @@ -686,7 +686,7 @@ #define RKISP1_CIF_CTRL_BASE 0x00000000 #define RKISP1_CIF_VI_CCL (RKISP1_CIF_CTRL_BASE + 0x00000000) #define RKISP1_CIF_VI_ID (RKISP1_CIF_CTRL_BASE + 0x00000008) -#define RKISP1_CIF_VI_ISP_CLK_CTRL_V12 (RKISP1_CIF_CTRL_BASE + 0x0000000C) +#define RKISP1_CIF_VI_ISP_CLK_CTRL_V12 (RKISP1_CIF_CTRL_BASE + 0x0000000c) #define RKISP1_CIF_VI_ICCL (RKISP1_CIF_CTRL_BASE + 0x00000010) #define RKISP1_CIF_VI_IRCL (RKISP1_CIF_CTRL_BASE + 0x00000014) #define RKISP1_CIF_VI_DPCL (RKISP1_CIF_CTRL_BASE + 0x00000018) @@ -695,11 +695,11 @@ #define RKISP1_CIF_IMG_EFF_CTRL (RKISP1_CIF_IMG_EFF_BASE + 0x00000000) #define RKISP1_CIF_IMG_EFF_COLOR_SEL (RKISP1_CIF_IMG_EFF_BASE + 0x00000004) #define RKISP1_CIF_IMG_EFF_MAT_1 (RKISP1_CIF_IMG_EFF_BASE + 0x00000008) -#define RKISP1_CIF_IMG_EFF_MAT_2 (RKISP1_CIF_IMG_EFF_BASE + 0x0000000C) +#define RKISP1_CIF_IMG_EFF_MAT_2 (RKISP1_CIF_IMG_EFF_BASE + 0x0000000c) #define RKISP1_CIF_IMG_EFF_MAT_3 (RKISP1_CIF_IMG_EFF_BASE + 0x00000010) #define RKISP1_CIF_IMG_EFF_MAT_4 (RKISP1_CIF_IMG_EFF_BASE + 0x00000014) #define RKISP1_CIF_IMG_EFF_MAT_5 (RKISP1_CIF_IMG_EFF_BASE + 0x00000018) -#define RKISP1_CIF_IMG_EFF_TINT (RKISP1_CIF_IMG_EFF_BASE + 0x0000001C) +#define RKISP1_CIF_IMG_EFF_TINT (RKISP1_CIF_IMG_EFF_BASE + 0x0000001c) #define RKISP1_CIF_IMG_EFF_CTRL_SHD (RKISP1_CIF_IMG_EFF_BASE + 0x00000020) #define RKISP1_CIF_IMG_EFF_SHARPEN (RKISP1_CIF_IMG_EFF_BASE + 0x00000024) @@ -707,7 +707,7 @@ #define RKISP1_CIF_SUPER_IMP_CTRL (RKISP1_CIF_SUPER_IMP_BASE + 0x00000000) #define RKISP1_CIF_SUPER_IMP_OFFSET_X (RKISP1_CIF_SUPER_IMP_BASE + 0x00000004) #define RKISP1_CIF_SUPER_IMP_OFFSET_Y (RKISP1_CIF_SUPER_IMP_BASE + 0x00000008) -#define RKISP1_CIF_SUPER_IMP_COLOR_Y (RKISP1_CIF_SUPER_IMP_BASE + 0x0000000C) +#define RKISP1_CIF_SUPER_IMP_COLOR_Y (RKISP1_CIF_SUPER_IMP_BASE + 0x0000000c) #define RKISP1_CIF_SUPER_IMP_COLOR_CB (RKISP1_CIF_SUPER_IMP_BASE + 0x00000010) #define RKISP1_CIF_SUPER_IMP_COLOR_CR (RKISP1_CIF_SUPER_IMP_BASE + 0x00000014) @@ -715,148 +715,148 @@ #define RKISP1_CIF_ISP_CTRL (RKISP1_CIF_ISP_BASE + 0x00000000) #define RKISP1_CIF_ISP_ACQ_PROP (RKISP1_CIF_ISP_BASE + 0x00000004) #define RKISP1_CIF_ISP_ACQ_H_OFFS (RKISP1_CIF_ISP_BASE + 0x00000008) -#define RKISP1_CIF_ISP_ACQ_V_OFFS (RKISP1_CIF_ISP_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_ACQ_V_OFFS (RKISP1_CIF_ISP_BASE + 0x0000000c) #define RKISP1_CIF_ISP_ACQ_H_SIZE (RKISP1_CIF_ISP_BASE + 0x00000010) #define RKISP1_CIF_ISP_ACQ_V_SIZE (RKISP1_CIF_ISP_BASE + 0x00000014) #define RKISP1_CIF_ISP_ACQ_NR_FRAMES (RKISP1_CIF_ISP_BASE + 0x00000018) -#define RKISP1_CIF_ISP_GAMMA_DX_LO (RKISP1_CIF_ISP_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_GAMMA_DX_LO (RKISP1_CIF_ISP_BASE + 0x0000001c) #define RKISP1_CIF_ISP_GAMMA_DX_HI (RKISP1_CIF_ISP_BASE + 0x00000020) #define RKISP1_CIF_ISP_GAMMA_R_Y0 (RKISP1_CIF_ISP_BASE + 0x00000024) #define RKISP1_CIF_ISP_GAMMA_R_Y1 (RKISP1_CIF_ISP_BASE + 0x00000028) -#define RKISP1_CIF_ISP_GAMMA_R_Y2 (RKISP1_CIF_ISP_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_GAMMA_R_Y2 (RKISP1_CIF_ISP_BASE + 0x0000002c) #define RKISP1_CIF_ISP_GAMMA_R_Y3 (RKISP1_CIF_ISP_BASE + 0x00000030) #define RKISP1_CIF_ISP_GAMMA_R_Y4 (RKISP1_CIF_ISP_BASE + 0x00000034) #define RKISP1_CIF_ISP_GAMMA_R_Y5 (RKISP1_CIF_ISP_BASE + 0x00000038) -#define RKISP1_CIF_ISP_GAMMA_R_Y6 (RKISP1_CIF_ISP_BASE + 0x0000003C) +#define RKISP1_CIF_ISP_GAMMA_R_Y6 (RKISP1_CIF_ISP_BASE + 0x0000003c) #define RKISP1_CIF_ISP_GAMMA_R_Y7 (RKISP1_CIF_ISP_BASE + 0x00000040) #define RKISP1_CIF_ISP_GAMMA_R_Y8 (RKISP1_CIF_ISP_BASE + 0x00000044) #define RKISP1_CIF_ISP_GAMMA_R_Y9 (RKISP1_CIF_ISP_BASE + 0x00000048) -#define RKISP1_CIF_ISP_GAMMA_R_Y10 (RKISP1_CIF_ISP_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_GAMMA_R_Y10 (RKISP1_CIF_ISP_BASE + 0x0000004c) #define RKISP1_CIF_ISP_GAMMA_R_Y11 (RKISP1_CIF_ISP_BASE + 0x00000050) #define RKISP1_CIF_ISP_GAMMA_R_Y12 (RKISP1_CIF_ISP_BASE + 0x00000054) #define RKISP1_CIF_ISP_GAMMA_R_Y13 (RKISP1_CIF_ISP_BASE + 0x00000058) -#define RKISP1_CIF_ISP_GAMMA_R_Y14 (RKISP1_CIF_ISP_BASE + 0x0000005C) +#define RKISP1_CIF_ISP_GAMMA_R_Y14 (RKISP1_CIF_ISP_BASE + 0x0000005c) #define RKISP1_CIF_ISP_GAMMA_R_Y15 (RKISP1_CIF_ISP_BASE + 0x00000060) #define RKISP1_CIF_ISP_GAMMA_R_Y16 (RKISP1_CIF_ISP_BASE + 0x00000064) #define RKISP1_CIF_ISP_GAMMA_G_Y0 (RKISP1_CIF_ISP_BASE + 0x00000068) -#define RKISP1_CIF_ISP_GAMMA_G_Y1 (RKISP1_CIF_ISP_BASE + 0x0000006C) +#define RKISP1_CIF_ISP_GAMMA_G_Y1 (RKISP1_CIF_ISP_BASE + 0x0000006c) #define RKISP1_CIF_ISP_GAMMA_G_Y2 (RKISP1_CIF_ISP_BASE + 0x00000070) #define RKISP1_CIF_ISP_GAMMA_G_Y3 (RKISP1_CIF_ISP_BASE + 0x00000074) #define RKISP1_CIF_ISP_GAMMA_G_Y4 (RKISP1_CIF_ISP_BASE + 0x00000078) -#define RKISP1_CIF_ISP_GAMMA_G_Y5 (RKISP1_CIF_ISP_BASE + 0x0000007C) +#define RKISP1_CIF_ISP_GAMMA_G_Y5 (RKISP1_CIF_ISP_BASE + 0x0000007c) #define RKISP1_CIF_ISP_GAMMA_G_Y6 (RKISP1_CIF_ISP_BASE + 0x00000080) #define RKISP1_CIF_ISP_GAMMA_G_Y7 (RKISP1_CIF_ISP_BASE + 0x00000084) #define RKISP1_CIF_ISP_GAMMA_G_Y8 (RKISP1_CIF_ISP_BASE + 0x00000088) -#define RKISP1_CIF_ISP_GAMMA_G_Y9 (RKISP1_CIF_ISP_BASE + 0x0000008C) +#define RKISP1_CIF_ISP_GAMMA_G_Y9 (RKISP1_CIF_ISP_BASE + 0x0000008c) #define RKISP1_CIF_ISP_GAMMA_G_Y10 (RKISP1_CIF_ISP_BASE + 0x00000090) #define RKISP1_CIF_ISP_GAMMA_G_Y11 (RKISP1_CIF_ISP_BASE + 0x00000094) #define RKISP1_CIF_ISP_GAMMA_G_Y12 (RKISP1_CIF_ISP_BASE + 0x00000098) -#define RKISP1_CIF_ISP_GAMMA_G_Y13 (RKISP1_CIF_ISP_BASE + 0x0000009C) -#define RKISP1_CIF_ISP_GAMMA_G_Y14 (RKISP1_CIF_ISP_BASE + 0x000000A0) -#define RKISP1_CIF_ISP_GAMMA_G_Y15 (RKISP1_CIF_ISP_BASE + 0x000000A4) -#define RKISP1_CIF_ISP_GAMMA_G_Y16 (RKISP1_CIF_ISP_BASE + 0x000000A8) -#define RKISP1_CIF_ISP_GAMMA_B_Y0 (RKISP1_CIF_ISP_BASE + 0x000000AC) -#define RKISP1_CIF_ISP_GAMMA_B_Y1 (RKISP1_CIF_ISP_BASE + 0x000000B0) -#define RKISP1_CIF_ISP_GAMMA_B_Y2 (RKISP1_CIF_ISP_BASE + 0x000000B4) -#define RKISP1_CIF_ISP_GAMMA_B_Y3 (RKISP1_CIF_ISP_BASE + 0x000000B8) -#define RKISP1_CIF_ISP_GAMMA_B_Y4 (RKISP1_CIF_ISP_BASE + 0x000000BC) -#define RKISP1_CIF_ISP_GAMMA_B_Y5 (RKISP1_CIF_ISP_BASE + 0x000000C0) -#define RKISP1_CIF_ISP_GAMMA_B_Y6 (RKISP1_CIF_ISP_BASE + 0x000000C4) -#define RKISP1_CIF_ISP_GAMMA_B_Y7 (RKISP1_CIF_ISP_BASE + 0x000000C8) -#define RKISP1_CIF_ISP_GAMMA_B_Y8 (RKISP1_CIF_ISP_BASE + 0x000000CC) -#define RKISP1_CIF_ISP_GAMMA_B_Y9 (RKISP1_CIF_ISP_BASE + 0x000000D0) -#define RKISP1_CIF_ISP_GAMMA_B_Y10 (RKISP1_CIF_ISP_BASE + 0x000000D4) -#define RKISP1_CIF_ISP_GAMMA_B_Y11 (RKISP1_CIF_ISP_BASE + 0x000000D8) -#define RKISP1_CIF_ISP_GAMMA_B_Y12 (RKISP1_CIF_ISP_BASE + 0x000000DC) -#define RKISP1_CIF_ISP_GAMMA_B_Y13 (RKISP1_CIF_ISP_BASE + 0x000000E0) -#define RKISP1_CIF_ISP_GAMMA_B_Y14 (RKISP1_CIF_ISP_BASE + 0x000000E4) -#define RKISP1_CIF_ISP_GAMMA_B_Y15 (RKISP1_CIF_ISP_BASE + 0x000000E8) -#define RKISP1_CIF_ISP_GAMMA_B_Y16 (RKISP1_CIF_ISP_BASE + 0x000000EC) +#define RKISP1_CIF_ISP_GAMMA_G_Y13 (RKISP1_CIF_ISP_BASE + 0x0000009c) +#define RKISP1_CIF_ISP_GAMMA_G_Y14 (RKISP1_CIF_ISP_BASE + 0x000000a0) +#define RKISP1_CIF_ISP_GAMMA_G_Y15 (RKISP1_CIF_ISP_BASE + 0x000000a4) +#define RKISP1_CIF_ISP_GAMMA_G_Y16 (RKISP1_CIF_ISP_BASE + 0x000000a8) +#define RKISP1_CIF_ISP_GAMMA_B_Y0 (RKISP1_CIF_ISP_BASE + 0x000000ac) +#define RKISP1_CIF_ISP_GAMMA_B_Y1 (RKISP1_CIF_ISP_BASE + 0x000000b0) +#define RKISP1_CIF_ISP_GAMMA_B_Y2 (RKISP1_CIF_ISP_BASE + 0x000000b4) +#define RKISP1_CIF_ISP_GAMMA_B_Y3 (RKISP1_CIF_ISP_BASE + 0x000000b8) +#define RKISP1_CIF_ISP_GAMMA_B_Y4 (RKISP1_CIF_ISP_BASE + 0x000000bc) +#define RKISP1_CIF_ISP_GAMMA_B_Y5 (RKISP1_CIF_ISP_BASE + 0x000000c0) +#define RKISP1_CIF_ISP_GAMMA_B_Y6 (RKISP1_CIF_ISP_BASE + 0x000000c4) +#define RKISP1_CIF_ISP_GAMMA_B_Y7 (RKISP1_CIF_ISP_BASE + 0x000000c8) +#define RKISP1_CIF_ISP_GAMMA_B_Y8 (RKISP1_CIF_ISP_BASE + 0x000000cc) +#define RKISP1_CIF_ISP_GAMMA_B_Y9 (RKISP1_CIF_ISP_BASE + 0x000000d0) +#define RKISP1_CIF_ISP_GAMMA_B_Y10 (RKISP1_CIF_ISP_BASE + 0x000000d4) +#define RKISP1_CIF_ISP_GAMMA_B_Y11 (RKISP1_CIF_ISP_BASE + 0x000000d8) +#define RKISP1_CIF_ISP_GAMMA_B_Y12 (RKISP1_CIF_ISP_BASE + 0x000000dc) +#define RKISP1_CIF_ISP_GAMMA_B_Y13 (RKISP1_CIF_ISP_BASE + 0x000000e0) +#define RKISP1_CIF_ISP_GAMMA_B_Y14 (RKISP1_CIF_ISP_BASE + 0x000000e4) +#define RKISP1_CIF_ISP_GAMMA_B_Y15 (RKISP1_CIF_ISP_BASE + 0x000000e8) +#define RKISP1_CIF_ISP_GAMMA_B_Y16 (RKISP1_CIF_ISP_BASE + 0x000000ec) #define RKISP1_CIF_ISP_AWB_PROP_V10 (RKISP1_CIF_ISP_BASE + 0x00000110) #define RKISP1_CIF_ISP_AWB_WND_H_OFFS_V10 (RKISP1_CIF_ISP_BASE + 0x00000114) #define RKISP1_CIF_ISP_AWB_WND_V_OFFS_V10 (RKISP1_CIF_ISP_BASE + 0x00000118) -#define RKISP1_CIF_ISP_AWB_WND_H_SIZE_V10 (RKISP1_CIF_ISP_BASE + 0x0000011C) +#define RKISP1_CIF_ISP_AWB_WND_H_SIZE_V10 (RKISP1_CIF_ISP_BASE + 0x0000011c) #define RKISP1_CIF_ISP_AWB_WND_V_SIZE_V10 (RKISP1_CIF_ISP_BASE + 0x00000120) #define RKISP1_CIF_ISP_AWB_FRAMES_V10 (RKISP1_CIF_ISP_BASE + 0x00000124) #define RKISP1_CIF_ISP_AWB_REF_V10 (RKISP1_CIF_ISP_BASE + 0x00000128) -#define RKISP1_CIF_ISP_AWB_THRESH_V10 (RKISP1_CIF_ISP_BASE + 0x0000012C) +#define RKISP1_CIF_ISP_AWB_THRESH_V10 (RKISP1_CIF_ISP_BASE + 0x0000012c) #define RKISP1_CIF_ISP_AWB_GAIN_G_V10 (RKISP1_CIF_ISP_BASE + 0x00000138) -#define RKISP1_CIF_ISP_AWB_GAIN_RB_V10 (RKISP1_CIF_ISP_BASE + 0x0000013C) +#define RKISP1_CIF_ISP_AWB_GAIN_RB_V10 (RKISP1_CIF_ISP_BASE + 0x0000013c) #define RKISP1_CIF_ISP_AWB_WHITE_CNT_V10 (RKISP1_CIF_ISP_BASE + 0x00000140) #define RKISP1_CIF_ISP_AWB_MEAN_V10 (RKISP1_CIF_ISP_BASE + 0x00000144) #define RKISP1_CIF_ISP_AWB_PROP_V12 (RKISP1_CIF_ISP_BASE + 0x00000110) #define RKISP1_CIF_ISP_AWB_SIZE_V12 (RKISP1_CIF_ISP_BASE + 0x00000114) #define RKISP1_CIF_ISP_AWB_OFFS_V12 (RKISP1_CIF_ISP_BASE + 0x00000118) -#define RKISP1_CIF_ISP_AWB_REF_V12 (RKISP1_CIF_ISP_BASE + 0x0000011C) +#define RKISP1_CIF_ISP_AWB_REF_V12 (RKISP1_CIF_ISP_BASE + 0x0000011c) #define RKISP1_CIF_ISP_AWB_THRESH_V12 (RKISP1_CIF_ISP_BASE + 0x00000120) #define RKISP1_CIF_ISP_X_COOR12_V12 (RKISP1_CIF_ISP_BASE + 0x00000124) #define RKISP1_CIF_ISP_X_COOR34_V12 (RKISP1_CIF_ISP_BASE + 0x00000128) -#define RKISP1_CIF_ISP_AWB_WHITE_CNT_V12 (RKISP1_CIF_ISP_BASE + 0x0000012C) +#define RKISP1_CIF_ISP_AWB_WHITE_CNT_V12 (RKISP1_CIF_ISP_BASE + 0x0000012c) #define RKISP1_CIF_ISP_AWB_MEAN_V12 (RKISP1_CIF_ISP_BASE + 0x00000130) #define RKISP1_CIF_ISP_DEGAIN_V12 (RKISP1_CIF_ISP_BASE + 0x00000134) #define RKISP1_CIF_ISP_AWB_GAIN_G_V12 (RKISP1_CIF_ISP_BASE + 0x00000138) -#define RKISP1_CIF_ISP_AWB_GAIN_RB_V12 (RKISP1_CIF_ISP_BASE + 0x0000013C) +#define RKISP1_CIF_ISP_AWB_GAIN_RB_V12 (RKISP1_CIF_ISP_BASE + 0x0000013c) #define RKISP1_CIF_ISP_REGION_LINE_V12 (RKISP1_CIF_ISP_BASE + 0x00000140) #define RKISP1_CIF_ISP_WP_CNT_REGION0_V12 (RKISP1_CIF_ISP_BASE + 0x00000160) #define RKISP1_CIF_ISP_WP_CNT_REGION1_V12 (RKISP1_CIF_ISP_BASE + 0x00000164) #define RKISP1_CIF_ISP_WP_CNT_REGION2_V12 (RKISP1_CIF_ISP_BASE + 0x00000168) -#define RKISP1_CIF_ISP_WP_CNT_REGION3_V12 (RKISP1_CIF_ISP_BASE + 0x0000016C) +#define RKISP1_CIF_ISP_WP_CNT_REGION3_V12 (RKISP1_CIF_ISP_BASE + 0x0000016c) #define RKISP1_CIF_ISP_CC_COEFF_0 (RKISP1_CIF_ISP_BASE + 0x00000170) #define RKISP1_CIF_ISP_CC_COEFF_1 (RKISP1_CIF_ISP_BASE + 0x00000174) #define RKISP1_CIF_ISP_CC_COEFF_2 (RKISP1_CIF_ISP_BASE + 0x00000178) -#define RKISP1_CIF_ISP_CC_COEFF_3 (RKISP1_CIF_ISP_BASE + 0x0000017C) +#define RKISP1_CIF_ISP_CC_COEFF_3 (RKISP1_CIF_ISP_BASE + 0x0000017c) #define RKISP1_CIF_ISP_CC_COEFF_4 (RKISP1_CIF_ISP_BASE + 0x00000180) #define RKISP1_CIF_ISP_CC_COEFF_5 (RKISP1_CIF_ISP_BASE + 0x00000184) #define RKISP1_CIF_ISP_CC_COEFF_6 (RKISP1_CIF_ISP_BASE + 0x00000188) -#define RKISP1_CIF_ISP_CC_COEFF_7 (RKISP1_CIF_ISP_BASE + 0x0000018C) +#define RKISP1_CIF_ISP_CC_COEFF_7 (RKISP1_CIF_ISP_BASE + 0x0000018c) #define RKISP1_CIF_ISP_CC_COEFF_8 (RKISP1_CIF_ISP_BASE + 0x00000190) #define RKISP1_CIF_ISP_OUT_H_OFFS (RKISP1_CIF_ISP_BASE + 0x00000194) #define RKISP1_CIF_ISP_OUT_V_OFFS (RKISP1_CIF_ISP_BASE + 0x00000198) -#define RKISP1_CIF_ISP_OUT_H_SIZE (RKISP1_CIF_ISP_BASE + 0x0000019C) -#define RKISP1_CIF_ISP_OUT_V_SIZE (RKISP1_CIF_ISP_BASE + 0x000001A0) -#define RKISP1_CIF_ISP_DEMOSAIC (RKISP1_CIF_ISP_BASE + 0x000001A4) -#define RKISP1_CIF_ISP_FLAGS_SHD (RKISP1_CIF_ISP_BASE + 0x000001A8) -#define RKISP1_CIF_ISP_OUT_H_OFFS_SHD (RKISP1_CIF_ISP_BASE + 0x000001AC) -#define RKISP1_CIF_ISP_OUT_V_OFFS_SHD (RKISP1_CIF_ISP_BASE + 0x000001B0) -#define RKISP1_CIF_ISP_OUT_H_SIZE_SHD (RKISP1_CIF_ISP_BASE + 0x000001B4) -#define RKISP1_CIF_ISP_OUT_V_SIZE_SHD (RKISP1_CIF_ISP_BASE + 0x000001B8) -#define RKISP1_CIF_ISP_IMSC (RKISP1_CIF_ISP_BASE + 0x000001BC) -#define RKISP1_CIF_ISP_RIS (RKISP1_CIF_ISP_BASE + 0x000001C0) -#define RKISP1_CIF_ISP_MIS (RKISP1_CIF_ISP_BASE + 0x000001C4) -#define RKISP1_CIF_ISP_ICR (RKISP1_CIF_ISP_BASE + 0x000001C8) -#define RKISP1_CIF_ISP_ISR (RKISP1_CIF_ISP_BASE + 0x000001CC) -#define RKISP1_CIF_ISP_CT_COEFF_0 (RKISP1_CIF_ISP_BASE + 0x000001D0) -#define RKISP1_CIF_ISP_CT_COEFF_1 (RKISP1_CIF_ISP_BASE + 0x000001D4) -#define RKISP1_CIF_ISP_CT_COEFF_2 (RKISP1_CIF_ISP_BASE + 0x000001D8) -#define RKISP1_CIF_ISP_CT_COEFF_3 (RKISP1_CIF_ISP_BASE + 0x000001DC) -#define RKISP1_CIF_ISP_CT_COEFF_4 (RKISP1_CIF_ISP_BASE + 0x000001E0) -#define RKISP1_CIF_ISP_CT_COEFF_5 (RKISP1_CIF_ISP_BASE + 0x000001E4) -#define RKISP1_CIF_ISP_CT_COEFF_6 (RKISP1_CIF_ISP_BASE + 0x000001E8) -#define RKISP1_CIF_ISP_CT_COEFF_7 (RKISP1_CIF_ISP_BASE + 0x000001EC) -#define RKISP1_CIF_ISP_CT_COEFF_8 (RKISP1_CIF_ISP_BASE + 0x000001F0) -#define RKISP1_CIF_ISP_GAMMA_OUT_MODE_V10 (RKISP1_CIF_ISP_BASE + 0x000001F4) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V10 (RKISP1_CIF_ISP_BASE + 0x000001F8) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_1_V10 (RKISP1_CIF_ISP_BASE + 0x000001FC) +#define RKISP1_CIF_ISP_OUT_H_SIZE (RKISP1_CIF_ISP_BASE + 0x0000019c) +#define RKISP1_CIF_ISP_OUT_V_SIZE (RKISP1_CIF_ISP_BASE + 0x000001a0) +#define RKISP1_CIF_ISP_DEMOSAIC (RKISP1_CIF_ISP_BASE + 0x000001a4) +#define RKISP1_CIF_ISP_FLAGS_SHD (RKISP1_CIF_ISP_BASE + 0x000001a8) +#define RKISP1_CIF_ISP_OUT_H_OFFS_SHD (RKISP1_CIF_ISP_BASE + 0x000001ac) +#define RKISP1_CIF_ISP_OUT_V_OFFS_SHD (RKISP1_CIF_ISP_BASE + 0x000001b0) +#define RKISP1_CIF_ISP_OUT_H_SIZE_SHD (RKISP1_CIF_ISP_BASE + 0x000001b4) +#define RKISP1_CIF_ISP_OUT_V_SIZE_SHD (RKISP1_CIF_ISP_BASE + 0x000001b8) +#define RKISP1_CIF_ISP_IMSC (RKISP1_CIF_ISP_BASE + 0x000001bc) +#define RKISP1_CIF_ISP_RIS (RKISP1_CIF_ISP_BASE + 0x000001c0) +#define RKISP1_CIF_ISP_MIS (RKISP1_CIF_ISP_BASE + 0x000001c4) +#define RKISP1_CIF_ISP_ICR (RKISP1_CIF_ISP_BASE + 0x000001c8) +#define RKISP1_CIF_ISP_ISR (RKISP1_CIF_ISP_BASE + 0x000001cc) +#define RKISP1_CIF_ISP_CT_COEFF_0 (RKISP1_CIF_ISP_BASE + 0x000001d0) +#define RKISP1_CIF_ISP_CT_COEFF_1 (RKISP1_CIF_ISP_BASE + 0x000001d4) +#define RKISP1_CIF_ISP_CT_COEFF_2 (RKISP1_CIF_ISP_BASE + 0x000001d8) +#define RKISP1_CIF_ISP_CT_COEFF_3 (RKISP1_CIF_ISP_BASE + 0x000001dc) +#define RKISP1_CIF_ISP_CT_COEFF_4 (RKISP1_CIF_ISP_BASE + 0x000001e0) +#define RKISP1_CIF_ISP_CT_COEFF_5 (RKISP1_CIF_ISP_BASE + 0x000001e4) +#define RKISP1_CIF_ISP_CT_COEFF_6 (RKISP1_CIF_ISP_BASE + 0x000001e8) +#define RKISP1_CIF_ISP_CT_COEFF_7 (RKISP1_CIF_ISP_BASE + 0x000001ec) +#define RKISP1_CIF_ISP_CT_COEFF_8 (RKISP1_CIF_ISP_BASE + 0x000001f0) +#define RKISP1_CIF_ISP_GAMMA_OUT_MODE_V10 (RKISP1_CIF_ISP_BASE + 0x000001f4) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V10 (RKISP1_CIF_ISP_BASE + 0x000001f8) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_1_V10 (RKISP1_CIF_ISP_BASE + 0x000001fc) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_2_V10 (RKISP1_CIF_ISP_BASE + 0x00000200) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_3_V10 (RKISP1_CIF_ISP_BASE + 0x00000204) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_4_V10 (RKISP1_CIF_ISP_BASE + 0x00000208) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_5_V10 (RKISP1_CIF_ISP_BASE + 0x0000020C) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_5_V10 (RKISP1_CIF_ISP_BASE + 0x0000020c) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_6_V10 (RKISP1_CIF_ISP_BASE + 0x00000210) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_7_V10 (RKISP1_CIF_ISP_BASE + 0x00000214) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_8_V10 (RKISP1_CIF_ISP_BASE + 0x00000218) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_9_V10 (RKISP1_CIF_ISP_BASE + 0x0000021C) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_9_V10 (RKISP1_CIF_ISP_BASE + 0x0000021c) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_10_V10 (RKISP1_CIF_ISP_BASE + 0x00000220) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_11_V10 (RKISP1_CIF_ISP_BASE + 0x00000224) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_12_V10 (RKISP1_CIF_ISP_BASE + 0x00000228) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_13_V10 (RKISP1_CIF_ISP_BASE + 0x0000022C) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_13_V10 (RKISP1_CIF_ISP_BASE + 0x0000022c) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_14_V10 (RKISP1_CIF_ISP_BASE + 0x00000230) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_15_V10 (RKISP1_CIF_ISP_BASE + 0x00000234) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_16_V10 (RKISP1_CIF_ISP_BASE + 0x00000238) -#define RKISP1_CIF_ISP_ERR (RKISP1_CIF_ISP_BASE + 0x0000023C) +#define RKISP1_CIF_ISP_ERR (RKISP1_CIF_ISP_BASE + 0x0000023c) #define RKISP1_CIF_ISP_ERR_CLR (RKISP1_CIF_ISP_BASE + 0x00000240) #define RKISP1_CIF_ISP_FRAME_COUNT (RKISP1_CIF_ISP_BASE + 0x00000244) #define RKISP1_CIF_ISP_CT_OFFSET_R (RKISP1_CIF_ISP_BASE + 0x00000248) -#define RKISP1_CIF_ISP_CT_OFFSET_G (RKISP1_CIF_ISP_BASE + 0x0000024C) +#define RKISP1_CIF_ISP_CT_OFFSET_G (RKISP1_CIF_ISP_BASE + 0x0000024c) #define RKISP1_CIF_ISP_CT_OFFSET_B (RKISP1_CIF_ISP_BASE + 0x00000250) #define RKISP1_CIF_ISP_GAMMA_OUT_MODE_V12 (RKISP1_CIF_ISP_BASE + 0x00000300) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V12 (RKISP1_CIF_ISP_BASE + 0x00000304) @@ -865,7 +865,7 @@ #define RKISP1_CIF_ISP_FLASH_CMD (RKISP1_CIF_ISP_FLASH_BASE + 0x00000000) #define RKISP1_CIF_ISP_FLASH_CONFIG (RKISP1_CIF_ISP_FLASH_BASE + 0x00000004) #define RKISP1_CIF_ISP_FLASH_PREDIV (RKISP1_CIF_ISP_FLASH_BASE + 0x00000008) -#define RKISP1_CIF_ISP_FLASH_DELAY (RKISP1_CIF_ISP_FLASH_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_FLASH_DELAY (RKISP1_CIF_ISP_FLASH_BASE + 0x0000000c) #define RKISP1_CIF_ISP_FLASH_TIME (RKISP1_CIF_ISP_FLASH_BASE + 0x00000010) #define RKISP1_CIF_ISP_FLASH_MAXP (RKISP1_CIF_ISP_FLASH_BASE + 0x00000014) @@ -873,56 +873,56 @@ #define RKISP1_CIF_ISP_SH_CTRL (RKISP1_CIF_ISP_SH_BASE + 0x00000000) #define RKISP1_CIF_ISP_SH_PREDIV (RKISP1_CIF_ISP_SH_BASE + 0x00000004) #define RKISP1_CIF_ISP_SH_DELAY (RKISP1_CIF_ISP_SH_BASE + 0x00000008) -#define RKISP1_CIF_ISP_SH_TIME (RKISP1_CIF_ISP_SH_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_SH_TIME (RKISP1_CIF_ISP_SH_BASE + 0x0000000c) #define RKISP1_CIF_C_PROC_BASE 0x00000800 #define RKISP1_CIF_C_PROC_CTRL (RKISP1_CIF_C_PROC_BASE + 0x00000000) #define RKISP1_CIF_C_PROC_CONTRAST (RKISP1_CIF_C_PROC_BASE + 0x00000004) #define RKISP1_CIF_C_PROC_BRIGHTNESS (RKISP1_CIF_C_PROC_BASE + 0x00000008) -#define RKISP1_CIF_C_PROC_SATURATION (RKISP1_CIF_C_PROC_BASE + 0x0000000C) +#define RKISP1_CIF_C_PROC_SATURATION (RKISP1_CIF_C_PROC_BASE + 0x0000000c) #define RKISP1_CIF_C_PROC_HUE (RKISP1_CIF_C_PROC_BASE + 0x00000010) #define RKISP1_CIF_DUAL_CROP_BASE 0x00000880 #define RKISP1_CIF_DUAL_CROP_CTRL (RKISP1_CIF_DUAL_CROP_BASE + 0x00000000) #define RKISP1_CIF_DUAL_CROP_M_H_OFFS (RKISP1_CIF_DUAL_CROP_BASE + 0x00000004) #define RKISP1_CIF_DUAL_CROP_M_V_OFFS (RKISP1_CIF_DUAL_CROP_BASE + 0x00000008) -#define RKISP1_CIF_DUAL_CROP_M_H_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x0000000C) +#define RKISP1_CIF_DUAL_CROP_M_H_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x0000000c) #define RKISP1_CIF_DUAL_CROP_M_V_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x00000010) #define RKISP1_CIF_DUAL_CROP_S_H_OFFS (RKISP1_CIF_DUAL_CROP_BASE + 0x00000014) #define RKISP1_CIF_DUAL_CROP_S_V_OFFS (RKISP1_CIF_DUAL_CROP_BASE + 0x00000018) -#define RKISP1_CIF_DUAL_CROP_S_H_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x0000001C) +#define RKISP1_CIF_DUAL_CROP_S_H_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x0000001c) #define RKISP1_CIF_DUAL_CROP_S_V_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x00000020) #define RKISP1_CIF_DUAL_CROP_M_H_OFFS_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000024) #define RKISP1_CIF_DUAL_CROP_M_V_OFFS_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000028) -#define RKISP1_CIF_DUAL_CROP_M_H_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x0000002C) +#define RKISP1_CIF_DUAL_CROP_M_H_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x0000002c) #define RKISP1_CIF_DUAL_CROP_M_V_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000030) #define RKISP1_CIF_DUAL_CROP_S_H_OFFS_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000034) #define RKISP1_CIF_DUAL_CROP_S_V_OFFS_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000038) -#define RKISP1_CIF_DUAL_CROP_S_H_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x0000003C) +#define RKISP1_CIF_DUAL_CROP_S_H_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x0000003c) #define RKISP1_CIF_DUAL_CROP_S_V_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000040) -#define RKISP1_CIF_MRSZ_BASE 0x00000C00 +#define RKISP1_CIF_MRSZ_BASE 0x00000c00 #define RKISP1_CIF_SRSZ_BASE 0x00001000 #define RKISP1_CIF_RSZ_CTRL 0x0000 #define RKISP1_CIF_RSZ_SCALE_HY 0x0004 #define RKISP1_CIF_RSZ_SCALE_HCB 0x0008 -#define RKISP1_CIF_RSZ_SCALE_HCR 0x000C +#define RKISP1_CIF_RSZ_SCALE_HCR 0x000c #define RKISP1_CIF_RSZ_SCALE_VY 0x0010 #define RKISP1_CIF_RSZ_SCALE_VC 0x0014 #define RKISP1_CIF_RSZ_PHASE_HY 0x0018 -#define RKISP1_CIF_RSZ_PHASE_HC 0x001C +#define RKISP1_CIF_RSZ_PHASE_HC 0x001c #define RKISP1_CIF_RSZ_PHASE_VY 0x0020 #define RKISP1_CIF_RSZ_PHASE_VC 0x0024 #define RKISP1_CIF_RSZ_SCALE_LUT_ADDR 0x0028 -#define RKISP1_CIF_RSZ_SCALE_LUT 0x002C +#define RKISP1_CIF_RSZ_SCALE_LUT 0x002c #define RKISP1_CIF_RSZ_CTRL_SHD 0x0030 #define RKISP1_CIF_RSZ_SCALE_HY_SHD 0x0034 #define RKISP1_CIF_RSZ_SCALE_HCB_SHD 0x0038 -#define RKISP1_CIF_RSZ_SCALE_HCR_SHD 0x003C +#define RKISP1_CIF_RSZ_SCALE_HCR_SHD 0x003c #define RKISP1_CIF_RSZ_SCALE_VY_SHD 0x0040 #define RKISP1_CIF_RSZ_SCALE_VC_SHD 0x0044 #define RKISP1_CIF_RSZ_PHASE_HY_SHD 0x0048 -#define RKISP1_CIF_RSZ_PHASE_HC_SHD 0x004C +#define RKISP1_CIF_RSZ_PHASE_HC_SHD 0x004c #define RKISP1_CIF_RSZ_PHASE_VY_SHD 0x0050 #define RKISP1_CIF_RSZ_PHASE_VC_SHD 0x0054 @@ -930,89 +930,89 @@ #define RKISP1_CIF_MI_CTRL (RKISP1_CIF_MI_BASE + 0x00000000) #define RKISP1_CIF_MI_INIT (RKISP1_CIF_MI_BASE + 0x00000004) #define RKISP1_CIF_MI_MP_Y_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x00000008) -#define RKISP1_CIF_MI_MP_Y_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x0000000C) +#define RKISP1_CIF_MI_MP_Y_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x0000000c) #define RKISP1_CIF_MI_MP_Y_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000010) #define RKISP1_CIF_MI_MP_Y_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x00000014) #define RKISP1_CIF_MI_MP_Y_IRQ_OFFS_INIT (RKISP1_CIF_MI_BASE + 0x00000018) -#define RKISP1_CIF_MI_MP_CB_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000001C) +#define RKISP1_CIF_MI_MP_CB_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000001c) #define RKISP1_CIF_MI_MP_CB_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000020) #define RKISP1_CIF_MI_MP_CB_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000024) #define RKISP1_CIF_MI_MP_CB_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x00000028) -#define RKISP1_CIF_MI_MP_CR_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000002C) +#define RKISP1_CIF_MI_MP_CR_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000002c) #define RKISP1_CIF_MI_MP_CR_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000030) #define RKISP1_CIF_MI_MP_CR_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000034) #define RKISP1_CIF_MI_MP_CR_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x00000038) -#define RKISP1_CIF_MI_SP_Y_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000003C) +#define RKISP1_CIF_MI_SP_Y_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000003c) #define RKISP1_CIF_MI_SP_Y_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000040) #define RKISP1_CIF_MI_SP_Y_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000044) #define RKISP1_CIF_MI_SP_Y_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x00000048) -#define RKISP1_CIF_MI_SP_Y_LLENGTH (RKISP1_CIF_MI_BASE + 0x0000004C) +#define RKISP1_CIF_MI_SP_Y_LLENGTH (RKISP1_CIF_MI_BASE + 0x0000004c) #define RKISP1_CIF_MI_SP_CB_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x00000050) #define RKISP1_CIF_MI_SP_CB_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000054) #define RKISP1_CIF_MI_SP_CB_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000058) -#define RKISP1_CIF_MI_SP_CB_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x0000005C) +#define RKISP1_CIF_MI_SP_CB_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x0000005c) #define RKISP1_CIF_MI_SP_CR_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x00000060) #define RKISP1_CIF_MI_SP_CR_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000064) #define RKISP1_CIF_MI_SP_CR_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000068) -#define RKISP1_CIF_MI_SP_CR_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x0000006C) +#define RKISP1_CIF_MI_SP_CR_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x0000006c) #define RKISP1_CIF_MI_BYTE_CNT (RKISP1_CIF_MI_BASE + 0x00000070) #define RKISP1_CIF_MI_CTRL_SHD (RKISP1_CIF_MI_BASE + 0x00000074) #define RKISP1_CIF_MI_MP_Y_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x00000078) -#define RKISP1_CIF_MI_MP_Y_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x0000007C) +#define RKISP1_CIF_MI_MP_Y_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x0000007c) #define RKISP1_CIF_MI_MP_Y_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x00000080) #define RKISP1_CIF_MI_MP_Y_IRQ_OFFS_SHD (RKISP1_CIF_MI_BASE + 0x00000084) #define RKISP1_CIF_MI_MP_CB_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x00000088) -#define RKISP1_CIF_MI_MP_CB_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x0000008C) +#define RKISP1_CIF_MI_MP_CB_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x0000008c) #define RKISP1_CIF_MI_MP_CB_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x00000090) #define RKISP1_CIF_MI_MP_CR_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x00000094) #define RKISP1_CIF_MI_MP_CR_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x00000098) -#define RKISP1_CIF_MI_MP_CR_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x0000009C) -#define RKISP1_CIF_MI_SP_Y_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000A0) -#define RKISP1_CIF_MI_SP_Y_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000A4) -#define RKISP1_CIF_MI_SP_Y_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000A8) -#define RKISP1_CIF_MI_SP_CB_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000B0) -#define RKISP1_CIF_MI_SP_CB_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000B4) -#define RKISP1_CIF_MI_SP_CB_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000B8) -#define RKISP1_CIF_MI_SP_CR_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000BC) -#define RKISP1_CIF_MI_SP_CR_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000C0) -#define RKISP1_CIF_MI_SP_CR_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000C4) -#define RKISP1_CIF_MI_DMA_Y_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000C8) -#define RKISP1_CIF_MI_DMA_Y_PIC_WIDTH (RKISP1_CIF_MI_BASE + 0x000000CC) -#define RKISP1_CIF_MI_DMA_Y_LLENGTH (RKISP1_CIF_MI_BASE + 0x000000D0) -#define RKISP1_CIF_MI_DMA_Y_PIC_SIZE (RKISP1_CIF_MI_BASE + 0x000000D4) -#define RKISP1_CIF_MI_DMA_CB_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000D8) -#define RKISP1_CIF_MI_DMA_CR_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000E8) -#define RKISP1_CIF_MI_IMSC (RKISP1_CIF_MI_BASE + 0x000000F8) -#define RKISP1_CIF_MI_RIS (RKISP1_CIF_MI_BASE + 0x000000FC) +#define RKISP1_CIF_MI_MP_CR_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x0000009c) +#define RKISP1_CIF_MI_SP_Y_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000a0) +#define RKISP1_CIF_MI_SP_Y_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000a4) +#define RKISP1_CIF_MI_SP_Y_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000a8) +#define RKISP1_CIF_MI_SP_CB_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000b0) +#define RKISP1_CIF_MI_SP_CB_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000b4) +#define RKISP1_CIF_MI_SP_CB_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000b8) +#define RKISP1_CIF_MI_SP_CR_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000bc) +#define RKISP1_CIF_MI_SP_CR_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000c0) +#define RKISP1_CIF_MI_SP_CR_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000c4) +#define RKISP1_CIF_MI_DMA_Y_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000c8) +#define RKISP1_CIF_MI_DMA_Y_PIC_WIDTH (RKISP1_CIF_MI_BASE + 0x000000cc) +#define RKISP1_CIF_MI_DMA_Y_LLENGTH (RKISP1_CIF_MI_BASE + 0x000000d0) +#define RKISP1_CIF_MI_DMA_Y_PIC_SIZE (RKISP1_CIF_MI_BASE + 0x000000d4) +#define RKISP1_CIF_MI_DMA_CB_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000d8) +#define RKISP1_CIF_MI_DMA_CR_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000e8) +#define RKISP1_CIF_MI_IMSC (RKISP1_CIF_MI_BASE + 0x000000f8) +#define RKISP1_CIF_MI_RIS (RKISP1_CIF_MI_BASE + 0x000000fc) #define RKISP1_CIF_MI_MIS (RKISP1_CIF_MI_BASE + 0x00000100) #define RKISP1_CIF_MI_ICR (RKISP1_CIF_MI_BASE + 0x00000104) #define RKISP1_CIF_MI_ISR (RKISP1_CIF_MI_BASE + 0x00000108) -#define RKISP1_CIF_MI_STATUS (RKISP1_CIF_MI_BASE + 0x0000010C) +#define RKISP1_CIF_MI_STATUS (RKISP1_CIF_MI_BASE + 0x0000010c) #define RKISP1_CIF_MI_STATUS_CLR (RKISP1_CIF_MI_BASE + 0x00000110) #define RKISP1_CIF_MI_SP_Y_PIC_WIDTH (RKISP1_CIF_MI_BASE + 0x00000114) #define RKISP1_CIF_MI_SP_Y_PIC_HEIGHT (RKISP1_CIF_MI_BASE + 0x00000118) -#define RKISP1_CIF_MI_SP_Y_PIC_SIZE (RKISP1_CIF_MI_BASE + 0x0000011C) +#define RKISP1_CIF_MI_SP_Y_PIC_SIZE (RKISP1_CIF_MI_BASE + 0x0000011c) #define RKISP1_CIF_MI_DMA_CTRL (RKISP1_CIF_MI_BASE + 0x00000120) #define RKISP1_CIF_MI_DMA_START (RKISP1_CIF_MI_BASE + 0x00000124) #define RKISP1_CIF_MI_DMA_STATUS (RKISP1_CIF_MI_BASE + 0x00000128) -#define RKISP1_CIF_MI_PIXEL_COUNT (RKISP1_CIF_MI_BASE + 0x0000012C) +#define RKISP1_CIF_MI_PIXEL_COUNT (RKISP1_CIF_MI_BASE + 0x0000012c) #define RKISP1_CIF_MI_MP_Y_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000130) #define RKISP1_CIF_MI_MP_CB_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000134) #define RKISP1_CIF_MI_MP_CR_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000138) -#define RKISP1_CIF_MI_SP_Y_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x0000013C) +#define RKISP1_CIF_MI_SP_Y_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x0000013c) #define RKISP1_CIF_MI_SP_CB_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000140) #define RKISP1_CIF_MI_SP_CR_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000144) #define RKISP1_CIF_MI_XTD_FORMAT_CTRL (RKISP1_CIF_MI_BASE + 0x00000148) -#define RKISP1_CIF_SMIA_BASE 0x00001A00 +#define RKISP1_CIF_SMIA_BASE 0x00001a00 #define RKISP1_CIF_SMIA_CTRL (RKISP1_CIF_SMIA_BASE + 0x00000000) #define RKISP1_CIF_SMIA_STATUS (RKISP1_CIF_SMIA_BASE + 0x00000004) #define RKISP1_CIF_SMIA_IMSC (RKISP1_CIF_SMIA_BASE + 0x00000008) -#define RKISP1_CIF_SMIA_RIS (RKISP1_CIF_SMIA_BASE + 0x0000000C) +#define RKISP1_CIF_SMIA_RIS (RKISP1_CIF_SMIA_BASE + 0x0000000c) #define RKISP1_CIF_SMIA_MIS (RKISP1_CIF_SMIA_BASE + 0x00000010) #define RKISP1_CIF_SMIA_ICR (RKISP1_CIF_SMIA_BASE + 0x00000014) #define RKISP1_CIF_SMIA_ISR (RKISP1_CIF_SMIA_BASE + 0x00000018) -#define RKISP1_CIF_SMIA_DATA_FORMAT_SEL (RKISP1_CIF_SMIA_BASE + 0x0000001C) +#define RKISP1_CIF_SMIA_DATA_FORMAT_SEL (RKISP1_CIF_SMIA_BASE + 0x0000001c) #define RKISP1_CIF_SMIA_SOF_EMB_DATA_LINES (RKISP1_CIF_SMIA_BASE + 0x00000020) #define RKISP1_CIF_SMIA_EMB_HSTART (RKISP1_CIF_SMIA_BASE + 0x00000024) #define RKISP1_CIF_SMIA_EMB_HSIZE (RKISP1_CIF_SMIA_BASE + 0x00000028) @@ -1021,27 +1021,27 @@ #define RKISP1_CIF_SMIA_EMB_DATA_FIFO (RKISP1_CIF_SMIA_BASE + 0x00000034) #define RKISP1_CIF_SMIA_EMB_DATA_WATERMARK (RKISP1_CIF_SMIA_BASE + 0x00000038) -#define RKISP1_CIF_MIPI_BASE 0x00001C00 +#define RKISP1_CIF_MIPI_BASE 0x00001c00 #define RKISP1_CIF_MIPI_CTRL (RKISP1_CIF_MIPI_BASE + 0x00000000) #define RKISP1_CIF_MIPI_STATUS (RKISP1_CIF_MIPI_BASE + 0x00000004) #define RKISP1_CIF_MIPI_IMSC (RKISP1_CIF_MIPI_BASE + 0x00000008) -#define RKISP1_CIF_MIPI_RIS (RKISP1_CIF_MIPI_BASE + 0x0000000C) +#define RKISP1_CIF_MIPI_RIS (RKISP1_CIF_MIPI_BASE + 0x0000000c) #define RKISP1_CIF_MIPI_MIS (RKISP1_CIF_MIPI_BASE + 0x00000010) #define RKISP1_CIF_MIPI_ICR (RKISP1_CIF_MIPI_BASE + 0x00000014) #define RKISP1_CIF_MIPI_ISR (RKISP1_CIF_MIPI_BASE + 0x00000018) -#define RKISP1_CIF_MIPI_CUR_DATA_ID (RKISP1_CIF_MIPI_BASE + 0x0000001C) +#define RKISP1_CIF_MIPI_CUR_DATA_ID (RKISP1_CIF_MIPI_BASE + 0x0000001c) #define RKISP1_CIF_MIPI_IMG_DATA_SEL (RKISP1_CIF_MIPI_BASE + 0x00000020) #define RKISP1_CIF_MIPI_ADD_DATA_SEL_1 (RKISP1_CIF_MIPI_BASE + 0x00000024) #define RKISP1_CIF_MIPI_ADD_DATA_SEL_2 (RKISP1_CIF_MIPI_BASE + 0x00000028) -#define RKISP1_CIF_MIPI_ADD_DATA_SEL_3 (RKISP1_CIF_MIPI_BASE + 0x0000002C) +#define RKISP1_CIF_MIPI_ADD_DATA_SEL_3 (RKISP1_CIF_MIPI_BASE + 0x0000002c) #define RKISP1_CIF_MIPI_ADD_DATA_SEL_4 (RKISP1_CIF_MIPI_BASE + 0x00000030) #define RKISP1_CIF_MIPI_ADD_DATA_FIFO (RKISP1_CIF_MIPI_BASE + 0x00000034) #define RKISP1_CIF_MIPI_FIFO_FILL_LEVEL (RKISP1_CIF_MIPI_BASE + 0x00000038) -#define RKISP1_CIF_MIPI_COMPRESSED_MODE (RKISP1_CIF_MIPI_BASE + 0x0000003C) +#define RKISP1_CIF_MIPI_COMPRESSED_MODE (RKISP1_CIF_MIPI_BASE + 0x0000003c) #define RKISP1_CIF_MIPI_FRAME (RKISP1_CIF_MIPI_BASE + 0x00000040) #define RKISP1_CIF_MIPI_GEN_SHORT_DT (RKISP1_CIF_MIPI_BASE + 0x00000044) #define RKISP1_CIF_MIPI_GEN_SHORT_8_9 (RKISP1_CIF_MIPI_BASE + 0x00000048) -#define RKISP1_CIF_MIPI_GEN_SHORT_A_B (RKISP1_CIF_MIPI_BASE + 0x0000004C) +#define RKISP1_CIF_MIPI_GEN_SHORT_A_B (RKISP1_CIF_MIPI_BASE + 0x0000004c) #define RKISP1_CIF_MIPI_GEN_SHORT_C_D (RKISP1_CIF_MIPI_BASE + 0x00000050) #define RKISP1_CIF_MIPI_GEN_SHORT_E_F (RKISP1_CIF_MIPI_BASE + 0x00000054) @@ -1049,15 +1049,15 @@ #define RKISP1_CIF_ISP_AFM_CTRL (RKISP1_CIF_ISP_AFM_BASE + 0x00000000) #define RKISP1_CIF_ISP_AFM_LT_A (RKISP1_CIF_ISP_AFM_BASE + 0x00000004) #define RKISP1_CIF_ISP_AFM_RB_A (RKISP1_CIF_ISP_AFM_BASE + 0x00000008) -#define RKISP1_CIF_ISP_AFM_LT_B (RKISP1_CIF_ISP_AFM_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_AFM_LT_B (RKISP1_CIF_ISP_AFM_BASE + 0x0000000c) #define RKISP1_CIF_ISP_AFM_RB_B (RKISP1_CIF_ISP_AFM_BASE + 0x00000010) #define RKISP1_CIF_ISP_AFM_LT_C (RKISP1_CIF_ISP_AFM_BASE + 0x00000014) #define RKISP1_CIF_ISP_AFM_RB_C (RKISP1_CIF_ISP_AFM_BASE + 0x00000018) -#define RKISP1_CIF_ISP_AFM_THRES (RKISP1_CIF_ISP_AFM_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_AFM_THRES (RKISP1_CIF_ISP_AFM_BASE + 0x0000001c) #define RKISP1_CIF_ISP_AFM_VAR_SHIFT (RKISP1_CIF_ISP_AFM_BASE + 0x00000020) #define RKISP1_CIF_ISP_AFM_SUM_A (RKISP1_CIF_ISP_AFM_BASE + 0x00000024) #define RKISP1_CIF_ISP_AFM_SUM_B (RKISP1_CIF_ISP_AFM_BASE + 0x00000028) -#define RKISP1_CIF_ISP_AFM_SUM_C (RKISP1_CIF_ISP_AFM_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_AFM_SUM_C (RKISP1_CIF_ISP_AFM_BASE + 0x0000002c) #define RKISP1_CIF_ISP_AFM_LUM_A (RKISP1_CIF_ISP_AFM_BASE + 0x00000030) #define RKISP1_CIF_ISP_AFM_LUM_B (RKISP1_CIF_ISP_AFM_BASE + 0x00000034) #define RKISP1_CIF_ISP_AFM_LUM_C (RKISP1_CIF_ISP_AFM_BASE + 0x00000038) @@ -1066,11 +1066,11 @@ #define RKISP1_CIF_ISP_LSC_CTRL (RKISP1_CIF_ISP_LSC_BASE + 0x00000000) #define RKISP1_CIF_ISP_LSC_R_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x00000004) #define RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x00000008) -#define RKISP1_CIF_ISP_LSC_B_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_LSC_B_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x0000000c) #define RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x00000010) #define RKISP1_CIF_ISP_LSC_R_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x00000014) #define RKISP1_CIF_ISP_LSC_GR_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x00000018) -#define RKISP1_CIF_ISP_LSC_B_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_LSC_B_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x0000001c) #define RKISP1_CIF_ISP_LSC_GB_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x00000020) #define RKISP1_CIF_ISP_LSC_XGRAD(n) (RKISP1_CIF_ISP_LSC_BASE + 0x00000024 + (n) * 4) #define RKISP1_CIF_ISP_LSC_YGRAD(n) (RKISP1_CIF_ISP_LSC_BASE + 0x00000034 + (n) * 4) @@ -1083,46 +1083,46 @@ #define RKISP1_CIF_ISP_IS_CTRL (RKISP1_CIF_ISP_IS_BASE + 0x00000000) #define RKISP1_CIF_ISP_IS_RECENTER (RKISP1_CIF_ISP_IS_BASE + 0x00000004) #define RKISP1_CIF_ISP_IS_H_OFFS (RKISP1_CIF_ISP_IS_BASE + 0x00000008) -#define RKISP1_CIF_ISP_IS_V_OFFS (RKISP1_CIF_ISP_IS_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_IS_V_OFFS (RKISP1_CIF_ISP_IS_BASE + 0x0000000c) #define RKISP1_CIF_ISP_IS_H_SIZE (RKISP1_CIF_ISP_IS_BASE + 0x00000010) #define RKISP1_CIF_ISP_IS_V_SIZE (RKISP1_CIF_ISP_IS_BASE + 0x00000014) #define RKISP1_CIF_ISP_IS_MAX_DX (RKISP1_CIF_ISP_IS_BASE + 0x00000018) -#define RKISP1_CIF_ISP_IS_MAX_DY (RKISP1_CIF_ISP_IS_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_IS_MAX_DY (RKISP1_CIF_ISP_IS_BASE + 0x0000001c) #define RKISP1_CIF_ISP_IS_DISPLACE (RKISP1_CIF_ISP_IS_BASE + 0x00000020) #define RKISP1_CIF_ISP_IS_H_OFFS_SHD (RKISP1_CIF_ISP_IS_BASE + 0x00000024) #define RKISP1_CIF_ISP_IS_V_OFFS_SHD (RKISP1_CIF_ISP_IS_BASE + 0x00000028) -#define RKISP1_CIF_ISP_IS_H_SIZE_SHD (RKISP1_CIF_ISP_IS_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_IS_H_SIZE_SHD (RKISP1_CIF_ISP_IS_BASE + 0x0000002c) #define RKISP1_CIF_ISP_IS_V_SIZE_SHD (RKISP1_CIF_ISP_IS_BASE + 0x00000030) #define RKISP1_CIF_ISP_HIST_BASE_V10 0x00002400 #define RKISP1_CIF_ISP_HIST_PROP_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000000) #define RKISP1_CIF_ISP_HIST_H_OFFS_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000004) #define RKISP1_CIF_ISP_HIST_V_OFFS_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000008) -#define RKISP1_CIF_ISP_HIST_H_SIZE_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000000C) +#define RKISP1_CIF_ISP_HIST_H_SIZE_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000000c) #define RKISP1_CIF_ISP_HIST_V_SIZE_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000010) #define RKISP1_CIF_ISP_HIST_BIN_0_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000014) #define RKISP1_CIF_ISP_HIST_BIN_1_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000018) -#define RKISP1_CIF_ISP_HIST_BIN_2_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000001C) +#define RKISP1_CIF_ISP_HIST_BIN_2_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000001c) #define RKISP1_CIF_ISP_HIST_BIN_3_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000020) #define RKISP1_CIF_ISP_HIST_BIN_4_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000024) #define RKISP1_CIF_ISP_HIST_BIN_5_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000028) -#define RKISP1_CIF_ISP_HIST_BIN_6_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000002C) +#define RKISP1_CIF_ISP_HIST_BIN_6_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000002c) #define RKISP1_CIF_ISP_HIST_BIN_7_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000030) #define RKISP1_CIF_ISP_HIST_BIN_8_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000034) #define RKISP1_CIF_ISP_HIST_BIN_9_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000038) -#define RKISP1_CIF_ISP_HIST_BIN_10_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000003C) +#define RKISP1_CIF_ISP_HIST_BIN_10_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000003c) #define RKISP1_CIF_ISP_HIST_BIN_11_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000040) #define RKISP1_CIF_ISP_HIST_BIN_12_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000044) #define RKISP1_CIF_ISP_HIST_BIN_13_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000048) -#define RKISP1_CIF_ISP_HIST_BIN_14_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000004C) +#define RKISP1_CIF_ISP_HIST_BIN_14_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000004c) #define RKISP1_CIF_ISP_HIST_BIN_15_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000050) #define RKISP1_CIF_ISP_HIST_WEIGHT_00TO30_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000054) #define RKISP1_CIF_ISP_HIST_WEIGHT_40TO21_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000058) -#define RKISP1_CIF_ISP_HIST_WEIGHT_31TO12_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000005C) +#define RKISP1_CIF_ISP_HIST_WEIGHT_31TO12_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000005c) #define RKISP1_CIF_ISP_HIST_WEIGHT_22TO03_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000060) #define RKISP1_CIF_ISP_HIST_WEIGHT_13TO43_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000064) #define RKISP1_CIF_ISP_HIST_WEIGHT_04TO34_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000068) -#define RKISP1_CIF_ISP_HIST_WEIGHT_44_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000006C) +#define RKISP1_CIF_ISP_HIST_WEIGHT_44_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000006c) #define RKISP1_CIF_ISP_FILT_BASE 0x00002500 #define RKISP1_CIF_ISP_FILT_MODE (RKISP1_CIF_ISP_FILT_BASE + 0x00000000) @@ -1135,13 +1135,13 @@ #define RKISP1_CIF_ISP_FILT_FAC_SH0 (RKISP1_CIF_ISP_FILT_BASE + 0x00000040) #define RKISP1_CIF_ISP_FILT_FAC_MID (RKISP1_CIF_ISP_FILT_BASE + 0x00000044) #define RKISP1_CIF_ISP_FILT_FAC_BL0 (RKISP1_CIF_ISP_FILT_BASE + 0x00000048) -#define RKISP1_CIF_ISP_FILT_FAC_BL1 (RKISP1_CIF_ISP_FILT_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_FILT_FAC_BL1 (RKISP1_CIF_ISP_FILT_BASE + 0x0000004c) #define RKISP1_CIF_ISP_CAC_BASE 0x00002580 #define RKISP1_CIF_ISP_CAC_CTRL (RKISP1_CIF_ISP_CAC_BASE + 0x00000000) #define RKISP1_CIF_ISP_CAC_COUNT_START (RKISP1_CIF_ISP_CAC_BASE + 0x00000004) #define RKISP1_CIF_ISP_CAC_A (RKISP1_CIF_ISP_CAC_BASE + 0x00000008) -#define RKISP1_CIF_ISP_CAC_B (RKISP1_CIF_ISP_CAC_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_CAC_B (RKISP1_CIF_ISP_CAC_BASE + 0x0000000c) #define RKISP1_CIF_ISP_CAC_C (RKISP1_CIF_ISP_CAC_BASE + 0x00000010) #define RKISP1_CIF_ISP_X_NORM (RKISP1_CIF_ISP_CAC_BASE + 0x00000014) #define RKISP1_CIF_ISP_Y_NORM (RKISP1_CIF_ISP_CAC_BASE + 0x00000018) @@ -1150,7 +1150,7 @@ #define RKISP1_CIF_ISP_EXP_CTRL (RKISP1_CIF_ISP_EXP_BASE + 0x00000000) #define RKISP1_CIF_ISP_EXP_H_OFFSET_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000004) #define RKISP1_CIF_ISP_EXP_V_OFFSET_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000008) -#define RKISP1_CIF_ISP_EXP_H_SIZE_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_EXP_H_SIZE_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x0000000c) #define RKISP1_CIF_ISP_EXP_V_SIZE_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000010) #define RKISP1_CIF_ISP_EXP_MEAN_00_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000014) #define RKISP1_CIF_ISP_EXP_MEAN_10_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000018) @@ -1205,160 +1205,160 @@ #define RKISP1_CIF_ISP_DPF_MODE (RKISP1_CIF_ISP_DPF_BASE + 0x00000000) #define RKISP1_CIF_ISP_DPF_STRENGTH_R (RKISP1_CIF_ISP_DPF_BASE + 0x00000004) #define RKISP1_CIF_ISP_DPF_STRENGTH_G (RKISP1_CIF_ISP_DPF_BASE + 0x00000008) -#define RKISP1_CIF_ISP_DPF_STRENGTH_B (RKISP1_CIF_ISP_DPF_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_DPF_STRENGTH_B (RKISP1_CIF_ISP_DPF_BASE + 0x0000000c) #define RKISP1_CIF_ISP_DPF_S_WEIGHT_G_1_4 (RKISP1_CIF_ISP_DPF_BASE + 0x00000010) #define RKISP1_CIF_ISP_DPF_S_WEIGHT_G_5_6 (RKISP1_CIF_ISP_DPF_BASE + 0x00000014) #define RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_1_4 (RKISP1_CIF_ISP_DPF_BASE + 0x00000018) -#define RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_5_6 (RKISP1_CIF_ISP_DPF_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_5_6 (RKISP1_CIF_ISP_DPF_BASE + 0x0000001c) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_0 (RKISP1_CIF_ISP_DPF_BASE + 0x00000020) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_1 (RKISP1_CIF_ISP_DPF_BASE + 0x00000024) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_2 (RKISP1_CIF_ISP_DPF_BASE + 0x00000028) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_3 (RKISP1_CIF_ISP_DPF_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_3 (RKISP1_CIF_ISP_DPF_BASE + 0x0000002c) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_4 (RKISP1_CIF_ISP_DPF_BASE + 0x00000030) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_5 (RKISP1_CIF_ISP_DPF_BASE + 0x00000034) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_6 (RKISP1_CIF_ISP_DPF_BASE + 0x00000038) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_7 (RKISP1_CIF_ISP_DPF_BASE + 0x0000003C) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_7 (RKISP1_CIF_ISP_DPF_BASE + 0x0000003c) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_8 (RKISP1_CIF_ISP_DPF_BASE + 0x00000040) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_9 (RKISP1_CIF_ISP_DPF_BASE + 0x00000044) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_10 (RKISP1_CIF_ISP_DPF_BASE + 0x00000048) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_11 (RKISP1_CIF_ISP_DPF_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_11 (RKISP1_CIF_ISP_DPF_BASE + 0x0000004c) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_12 (RKISP1_CIF_ISP_DPF_BASE + 0x00000050) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_13 (RKISP1_CIF_ISP_DPF_BASE + 0x00000054) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_14 (RKISP1_CIF_ISP_DPF_BASE + 0x00000058) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_15 (RKISP1_CIF_ISP_DPF_BASE + 0x0000005C) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_15 (RKISP1_CIF_ISP_DPF_BASE + 0x0000005c) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_16 (RKISP1_CIF_ISP_DPF_BASE + 0x00000060) #define RKISP1_CIF_ISP_DPF_NF_GAIN_R (RKISP1_CIF_ISP_DPF_BASE + 0x00000064) #define RKISP1_CIF_ISP_DPF_NF_GAIN_GR (RKISP1_CIF_ISP_DPF_BASE + 0x00000068) -#define RKISP1_CIF_ISP_DPF_NF_GAIN_GB (RKISP1_CIF_ISP_DPF_BASE + 0x0000006C) +#define RKISP1_CIF_ISP_DPF_NF_GAIN_GB (RKISP1_CIF_ISP_DPF_BASE + 0x0000006c) #define RKISP1_CIF_ISP_DPF_NF_GAIN_B (RKISP1_CIF_ISP_DPF_BASE + 0x00000070) #define RKISP1_CIF_ISP_DPCC_BASE 0x00002900 #define RKISP1_CIF_ISP_DPCC_MODE (RKISP1_CIF_ISP_DPCC_BASE + 0x00000000) #define RKISP1_CIF_ISP_DPCC_OUTPUT_MODE (RKISP1_CIF_ISP_DPCC_BASE + 0x00000004) #define RKISP1_CIF_ISP_DPCC_SET_USE (RKISP1_CIF_ISP_DPCC_BASE + 0x00000008) -#define RKISP1_CIF_ISP_DPCC_METHODS_SET_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000000c) #define RKISP1_CIF_ISP_DPCC_METHODS_SET_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000010) #define RKISP1_CIF_ISP_DPCC_METHODS_SET_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000014) #define RKISP1_CIF_ISP_DPCC_LINE_THRESH_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000018) -#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000001c) #define RKISP1_CIF_ISP_DPCC_PG_FAC_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000020) #define RKISP1_CIF_ISP_DPCC_RND_THRESH_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000024) #define RKISP1_CIF_ISP_DPCC_RG_FAC_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000028) -#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000002c) #define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000030) #define RKISP1_CIF_ISP_DPCC_PG_FAC_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000034) #define RKISP1_CIF_ISP_DPCC_RND_THRESH_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000038) -#define RKISP1_CIF_ISP_DPCC_RG_FAC_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000003C) +#define RKISP1_CIF_ISP_DPCC_RG_FAC_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000003c) #define RKISP1_CIF_ISP_DPCC_LINE_THRESH_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000040) #define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000044) #define RKISP1_CIF_ISP_DPCC_PG_FAC_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000048) -#define RKISP1_CIF_ISP_DPCC_RND_THRESH_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_DPCC_RND_THRESH_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000004c) #define RKISP1_CIF_ISP_DPCC_RG_FAC_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000050) #define RKISP1_CIF_ISP_DPCC_RO_LIMITS (RKISP1_CIF_ISP_DPCC_BASE + 0x00000054) #define RKISP1_CIF_ISP_DPCC_RND_OFFS (RKISP1_CIF_ISP_DPCC_BASE + 0x00000058) -#define RKISP1_CIF_ISP_DPCC_BPT_CTRL (RKISP1_CIF_ISP_DPCC_BASE + 0x0000005C) +#define RKISP1_CIF_ISP_DPCC_BPT_CTRL (RKISP1_CIF_ISP_DPCC_BASE + 0x0000005c) #define RKISP1_CIF_ISP_DPCC_BPT_NUMBER (RKISP1_CIF_ISP_DPCC_BASE + 0x00000060) #define RKISP1_CIF_ISP_DPCC_BPT_ADDR (RKISP1_CIF_ISP_DPCC_BASE + 0x00000064) #define RKISP1_CIF_ISP_DPCC_BPT_DATA (RKISP1_CIF_ISP_DPCC_BASE + 0x00000068) -#define RKISP1_CIF_ISP_WDR_BASE 0x00002A00 +#define RKISP1_CIF_ISP_WDR_BASE 0x00002a00 #define RKISP1_CIF_ISP_WDR_CTRL (RKISP1_CIF_ISP_WDR_BASE + 0x00000000) #define RKISP1_CIF_ISP_WDR_TONECURVE_1 (RKISP1_CIF_ISP_WDR_BASE + 0x00000004) #define RKISP1_CIF_ISP_WDR_TONECURVE_2 (RKISP1_CIF_ISP_WDR_BASE + 0x00000008) -#define RKISP1_CIF_ISP_WDR_TONECURVE_3 (RKISP1_CIF_ISP_WDR_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_3 (RKISP1_CIF_ISP_WDR_BASE + 0x0000000c) #define RKISP1_CIF_ISP_WDR_TONECURVE_4 (RKISP1_CIF_ISP_WDR_BASE + 0x00000010) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_0 (RKISP1_CIF_ISP_WDR_BASE + 0x00000014) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_1 (RKISP1_CIF_ISP_WDR_BASE + 0x00000018) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_2 (RKISP1_CIF_ISP_WDR_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_2 (RKISP1_CIF_ISP_WDR_BASE + 0x0000001c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_3 (RKISP1_CIF_ISP_WDR_BASE + 0x00000020) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_4 (RKISP1_CIF_ISP_WDR_BASE + 0x00000024) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_5 (RKISP1_CIF_ISP_WDR_BASE + 0x00000028) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_6 (RKISP1_CIF_ISP_WDR_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_6 (RKISP1_CIF_ISP_WDR_BASE + 0x0000002c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_7 (RKISP1_CIF_ISP_WDR_BASE + 0x00000030) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_8 (RKISP1_CIF_ISP_WDR_BASE + 0x00000034) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_9 (RKISP1_CIF_ISP_WDR_BASE + 0x00000038) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_10 (RKISP1_CIF_ISP_WDR_BASE + 0x0000003C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_10 (RKISP1_CIF_ISP_WDR_BASE + 0x0000003c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_11 (RKISP1_CIF_ISP_WDR_BASE + 0x00000040) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_12 (RKISP1_CIF_ISP_WDR_BASE + 0x00000044) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_13 (RKISP1_CIF_ISP_WDR_BASE + 0x00000048) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_14 (RKISP1_CIF_ISP_WDR_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_14 (RKISP1_CIF_ISP_WDR_BASE + 0x0000004c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_15 (RKISP1_CIF_ISP_WDR_BASE + 0x00000050) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_16 (RKISP1_CIF_ISP_WDR_BASE + 0x00000054) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_17 (RKISP1_CIF_ISP_WDR_BASE + 0x00000058) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_18 (RKISP1_CIF_ISP_WDR_BASE + 0x0000005C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_18 (RKISP1_CIF_ISP_WDR_BASE + 0x0000005c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_19 (RKISP1_CIF_ISP_WDR_BASE + 0x00000060) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_20 (RKISP1_CIF_ISP_WDR_BASE + 0x00000064) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_21 (RKISP1_CIF_ISP_WDR_BASE + 0x00000068) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_22 (RKISP1_CIF_ISP_WDR_BASE + 0x0000006C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_22 (RKISP1_CIF_ISP_WDR_BASE + 0x0000006c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_23 (RKISP1_CIF_ISP_WDR_BASE + 0x00000070) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_24 (RKISP1_CIF_ISP_WDR_BASE + 0x00000074) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_25 (RKISP1_CIF_ISP_WDR_BASE + 0x00000078) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_26 (RKISP1_CIF_ISP_WDR_BASE + 0x0000007C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_26 (RKISP1_CIF_ISP_WDR_BASE + 0x0000007c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_27 (RKISP1_CIF_ISP_WDR_BASE + 0x00000080) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_28 (RKISP1_CIF_ISP_WDR_BASE + 0x00000084) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_29 (RKISP1_CIF_ISP_WDR_BASE + 0x00000088) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_30 (RKISP1_CIF_ISP_WDR_BASE + 0x0000008C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_30 (RKISP1_CIF_ISP_WDR_BASE + 0x0000008c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_31 (RKISP1_CIF_ISP_WDR_BASE + 0x00000090) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_32 (RKISP1_CIF_ISP_WDR_BASE + 0x00000094) #define RKISP1_CIF_ISP_WDR_OFFSET (RKISP1_CIF_ISP_WDR_BASE + 0x00000098) -#define RKISP1_CIF_ISP_WDR_DELTAMIN (RKISP1_CIF_ISP_WDR_BASE + 0x0000009C) -#define RKISP1_CIF_ISP_WDR_TONECURVE_1_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000A0) -#define RKISP1_CIF_ISP_WDR_TONECURVE_2_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000A4) -#define RKISP1_CIF_ISP_WDR_TONECURVE_3_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000A8) -#define RKISP1_CIF_ISP_WDR_TONECURVE_4_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000AC) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_0_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000B0) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_1_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000B4) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_2_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000B8) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_3_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000BC) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_4_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000C0) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_5_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000C4) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_6_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000C8) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_7_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000CC) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_8_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000D0) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_9_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000D4) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_10_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000D8) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_11_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000DC) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_12_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000E0) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_13_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000E4) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_14_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000E8) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_15_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000EC) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_16_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000F0) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_17_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000F4) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_18_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000F8) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_19_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000FC) +#define RKISP1_CIF_ISP_WDR_DELTAMIN (RKISP1_CIF_ISP_WDR_BASE + 0x0000009c) +#define RKISP1_CIF_ISP_WDR_TONECURVE_1_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000a0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_2_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000a4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_3_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000a8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_4_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000ac) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_0_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000b0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_1_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000b4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_2_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000b8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_3_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000bc) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_4_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000c0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_5_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000c4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_6_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000c8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_7_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000cc) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_8_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000d0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_9_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000d4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_10_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000d8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_11_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000dc) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_12_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000e0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_13_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000e4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_14_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000e8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_15_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000ec) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_16_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000f0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_17_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000f4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_18_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000f8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_19_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000fc) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_20_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000100) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_21_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000104) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_22_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000108) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_23_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000010C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_23_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000010c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_24_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000110) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_25_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000114) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_26_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000118) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_27_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000011C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_27_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000011c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_28_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000120) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_29_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000124) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_30_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000128) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_31_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000012C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_31_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000012c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_32_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000130) -#define RKISP1_CIF_ISP_HIST_BASE_V12 0x00002C00 +#define RKISP1_CIF_ISP_HIST_BASE_V12 0x00002c00 #define RKISP1_CIF_ISP_HIST_CTRL_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x00000000) #define RKISP1_CIF_ISP_HIST_SIZE_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x00000004) #define RKISP1_CIF_ISP_HIST_OFFS_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x00000008) -#define RKISP1_CIF_ISP_HIST_DBG1_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x0000000C) -#define RKISP1_CIF_ISP_HIST_DBG2_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x0000001C) -#define RKISP1_CIF_ISP_HIST_DBG3_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x0000002C) -#define RKISP1_CIF_ISP_HIST_WEIGHT_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x0000003C) +#define RKISP1_CIF_ISP_HIST_DBG1_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x0000000c) +#define RKISP1_CIF_ISP_HIST_DBG2_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x0000001c) +#define RKISP1_CIF_ISP_HIST_DBG3_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x0000002c) +#define RKISP1_CIF_ISP_HIST_WEIGHT_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x0000003c) #define RKISP1_CIF_ISP_HIST_BIN_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x00000120) -#define RKISP1_CIF_ISP_VSM_BASE 0x00002F00 +#define RKISP1_CIF_ISP_VSM_BASE 0x00002f00 #define RKISP1_CIF_ISP_VSM_MODE (RKISP1_CIF_ISP_VSM_BASE + 0x00000000) #define RKISP1_CIF_ISP_VSM_H_OFFS (RKISP1_CIF_ISP_VSM_BASE + 0x00000004) #define RKISP1_CIF_ISP_VSM_V_OFFS (RKISP1_CIF_ISP_VSM_BASE + 0x00000008) -#define RKISP1_CIF_ISP_VSM_H_SIZE (RKISP1_CIF_ISP_VSM_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_VSM_H_SIZE (RKISP1_CIF_ISP_VSM_BASE + 0x0000000c) #define RKISP1_CIF_ISP_VSM_V_SIZE (RKISP1_CIF_ISP_VSM_BASE + 0x00000010) #define RKISP1_CIF_ISP_VSM_H_SEGMENTS (RKISP1_CIF_ISP_VSM_BASE + 0x00000014) #define RKISP1_CIF_ISP_VSM_V_SEGMENTS (RKISP1_CIF_ISP_VSM_BASE + 0x00000018) -#define RKISP1_CIF_ISP_VSM_DELTA_H (RKISP1_CIF_ISP_VSM_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_VSM_DELTA_H (RKISP1_CIF_ISP_VSM_BASE + 0x0000001c) #define RKISP1_CIF_ISP_VSM_DELTA_V (RKISP1_CIF_ISP_VSM_BASE + 0x00000020) #define RKISP1_CIF_ISP_CSI0_BASE 0x00007000 -- GitLab From 1f3ba4b8d4bb54cdbe46a372081bdcbc6632c602 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 13 Mar 2023 20:51:51 +0200 Subject: [PATCH 0554/1451] media: rkisp1: Constify rkisp1_v12_params_ops The rkisp1_v12_params_ops global variable doesn't need to be modified. Make it const. Signed-off-by: Laurent Pinchart Reviewed-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/platform/rockchip/rkisp1/rkisp1-params.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index 8e3dc4966b947..173d1ea418748 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -1726,7 +1726,7 @@ static const struct rkisp1_params_ops rkisp1_v10_params_ops = { .afm_config = rkisp1_afm_config_v10, }; -static struct rkisp1_params_ops rkisp1_v12_params_ops = { +static const struct rkisp1_params_ops rkisp1_v12_params_ops = { .lsc_matrix_config = rkisp1_lsc_matrix_config_v12, .goc_config = rkisp1_goc_config_v12, .awb_meas_config = rkisp1_awb_meas_config_v12, -- GitLab From 5964c90a04291e1fb94d65b5641b526316e48830 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 27 Apr 2023 11:43:17 +0300 Subject: [PATCH 0555/1451] media: rkisp1: Fix line stride calculation The line stride is expressed in the hardware as a number of pixels for the first plane. The bytesperline must thus be a multiple of the first plane's bpp value. Enforce this constraint. Signed-off-by: Laurent Pinchart Reviewed-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../platform/rockchip/rkisp1/rkisp1-capture.c | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c index 8f3cba3197623..3c1e2c1a8bbe9 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -1101,14 +1101,20 @@ rkisp1_fill_pixfmt(struct v4l2_pix_format_mplane *pixm, memset(pixm->plane_fmt, 0, sizeof(pixm->plane_fmt)); info = v4l2_format_info(pixm->pixelformat); pixm->num_planes = info->mem_planes; - stride = info->bpp[0] * pixm->width; - /* Self path supports custom stride but Main path doesn't */ - if (id == RKISP1_MAINPATH || plane_y->bytesperline < stride) - plane_y->bytesperline = stride; - plane_y->sizeimage = plane_y->bytesperline * pixm->height; - /* normalize stride to pixels per line */ - stride = DIV_ROUND_UP(plane_y->bytesperline, info->bpp[0]); + /* + * The SP supports custom strides, expressed as a number of pixels for + * the Y plane. Clamp the stride to a reasonable value to avoid integer + * overflows when calculating the bytesperline and sizeimage values. + */ + if (id == RKISP1_SELFPATH) + stride = clamp(DIV_ROUND_UP(plane_y->bytesperline, info->bpp[0]), + pixm->width, 65536U); + else + stride = pixm->width; + + plane_y->bytesperline = stride * info->bpp[0]; + plane_y->sizeimage = plane_y->bytesperline * pixm->height; for (i = 1; i < info->comp_planes; i++) { struct v4l2_plane_pix_format *plane = &pixm->plane_fmt[i]; -- GitLab From 7bf62fa39bf5c89d92962dce0022ef59ec52a2a0 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 23 Sep 2023 20:23:43 +0300 Subject: [PATCH 0556/1451] media: rkisp1: Remove dual crop control register from config structure The dual crop register is the same for both the MP and SP channels. Drop it from the rkisp1_rsz_config structure and use the RKISP1_CIF_DUAL_CROP_CTRL macro directly in the code. Signed-off-by: Laurent Pinchart Reviewed-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../media/platform/rockchip/rkisp1/rkisp1-resizer.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c index 6845df38ef5fe..bca111711cee7 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c @@ -60,7 +60,6 @@ struct rkisp1_rsz_config { const int min_rsz_height; /* registers */ struct { - u32 ctrl; u32 yuvmode_mask; u32 rawmode_mask; u32 h_offset; @@ -78,7 +77,6 @@ static const struct rkisp1_rsz_config rkisp1_rsz_config_mp = { .min_rsz_height = RKISP1_RSZ_SRC_MIN_HEIGHT, /* registers */ .dual_crop = { - .ctrl = RKISP1_CIF_DUAL_CROP_CTRL, .yuvmode_mask = RKISP1_CIF_DUAL_CROP_MP_MODE_YUV, .rawmode_mask = RKISP1_CIF_DUAL_CROP_MP_MODE_RAW, .h_offset = RKISP1_CIF_DUAL_CROP_M_H_OFFS, @@ -96,7 +94,6 @@ static const struct rkisp1_rsz_config rkisp1_rsz_config_sp = { .min_rsz_height = RKISP1_RSZ_SRC_MIN_HEIGHT, /* registers */ .dual_crop = { - .ctrl = RKISP1_CIF_DUAL_CROP_CTRL, .yuvmode_mask = RKISP1_CIF_DUAL_CROP_SP_MODE_YUV, .rawmode_mask = RKISP1_CIF_DUAL_CROP_SP_MODE_RAW, .h_offset = RKISP1_CIF_DUAL_CROP_S_H_OFFS, @@ -124,7 +121,7 @@ static inline void rkisp1_rsz_write(struct rkisp1_resizer *rsz, u32 offset, static void rkisp1_dcrop_disable(struct rkisp1_resizer *rsz, enum rkisp1_shadow_regs_when when) { - u32 dc_ctrl = rkisp1_read(rsz->rkisp1, rsz->config->dual_crop.ctrl); + u32 dc_ctrl = rkisp1_read(rsz->rkisp1, RKISP1_CIF_DUAL_CROP_CTRL); u32 mask = ~(rsz->config->dual_crop.yuvmode_mask | rsz->config->dual_crop.rawmode_mask); @@ -133,7 +130,7 @@ static void rkisp1_dcrop_disable(struct rkisp1_resizer *rsz, dc_ctrl |= RKISP1_CIF_DUAL_CROP_GEN_CFG_UPD; else dc_ctrl |= RKISP1_CIF_DUAL_CROP_CFG_UPD; - rkisp1_write(rsz->rkisp1, rsz->config->dual_crop.ctrl, dc_ctrl); + rkisp1_write(rsz->rkisp1, RKISP1_CIF_DUAL_CROP_CTRL, dc_ctrl); } /* configure dual-crop unit */ @@ -158,14 +155,14 @@ static void rkisp1_dcrop_config(struct rkisp1_resizer *rsz, return; } - dc_ctrl = rkisp1_read(rkisp1, rsz->config->dual_crop.ctrl); + dc_ctrl = rkisp1_read(rkisp1, RKISP1_CIF_DUAL_CROP_CTRL); rkisp1_write(rkisp1, rsz->config->dual_crop.h_offset, sink_crop->left); rkisp1_write(rkisp1, rsz->config->dual_crop.v_offset, sink_crop->top); rkisp1_write(rkisp1, rsz->config->dual_crop.h_size, sink_crop->width); rkisp1_write(rkisp1, rsz->config->dual_crop.v_size, sink_crop->height); dc_ctrl |= rsz->config->dual_crop.yuvmode_mask; dc_ctrl |= RKISP1_CIF_DUAL_CROP_CFG_UPD; - rkisp1_write(rkisp1, rsz->config->dual_crop.ctrl, dc_ctrl); + rkisp1_write(rkisp1, RKISP1_CIF_DUAL_CROP_CTRL, dc_ctrl); dev_dbg(rkisp1->dev, "stream %d crop: %dx%d -> %dx%d\n", rsz->id, sink_fmt->width, sink_fmt->height, -- GitLab From f4bc9c79a55a40608a405700a574303e4b90b310 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 27 Apr 2023 11:43:17 +0300 Subject: [PATCH 0557/1451] media: rkisp1: Program RKISP1_CIF_MI_SP_Y_PIC_SIZE register The self path has a Y_PIC_SIZE register that needs to be programmed to the total number of pixels, including the stride. This isn't done by the driver, fix it. While at it, reorder the register write order to sort them by address. Signed-off-by: Laurent Pinchart Reviewed-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c index 3c1e2c1a8bbe9..c6d7e01c89494 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -479,9 +479,11 @@ static void rkisp1_sp_config(struct rkisp1_capture *cap) rkisp1_write(rkisp1, cap->config->mi.cr_size_init, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR)); + rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_LLENGTH, cap->sp_y_stride); rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_WIDTH, pixm->width); rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_HEIGHT, pixm->height); - rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_LLENGTH, cap->sp_y_stride); + rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_SIZE, + cap->sp_y_stride * pixm->height); rkisp1_irq_frame_end_enable(cap); -- GitLab From 1a6ae627af1477e7dbc081c21102bb5d8889adb1 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 23 Sep 2023 22:49:06 +0300 Subject: [PATCH 0558/1451] media: rkisp1: resizer: Constify argument and local variables Pointers to v4l2_mbus_framefmt and v4l2_rect instances don't need to be modified when configuring the resizer. Make them const. Signed-off-by: Laurent Pinchart Reviewed-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../media/platform/rockchip/rkisp1/rkisp1-resizer.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c index bca111711cee7..26f9c16ccc3e8 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c @@ -206,10 +206,10 @@ static void rkisp1_rsz_disable(struct rkisp1_resizer *rsz, } static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz, - struct v4l2_rect *sink_y, - struct v4l2_rect *sink_c, - struct v4l2_rect *src_y, - struct v4l2_rect *src_c, + const struct v4l2_rect *sink_y, + const struct v4l2_rect *sink_c, + const struct v4l2_rect *src_y, + const struct v4l2_rect *src_c, enum rkisp1_shadow_regs_when when) { u32 ratio, rsz_ctrl = 0; @@ -270,9 +270,9 @@ static void rkisp1_rsz_config(struct rkisp1_resizer *rsz, enum rkisp1_shadow_regs_when when) { const struct rkisp1_rsz_yuv_mbus_info *sink_yuv_info, *src_yuv_info; + const struct v4l2_mbus_framefmt *src_fmt, *sink_fmt; + const struct v4l2_rect *sink_crop; struct v4l2_rect sink_y, sink_c, src_y, src_c; - struct v4l2_mbus_framefmt *src_fmt, *sink_fmt; - struct v4l2_rect *sink_crop; sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, RKISP1_RSZ_PAD_SINK); -- GitLab From 603fbdc1122565dd5bb3fc0b3f574afe5ac49cd9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 23 Sep 2023 22:49:06 +0300 Subject: [PATCH 0559/1451] media: rkisp1: resizer: Use v4l2_area instead of v4l2_rect to store size The rkisp1_rsz_config() and rkisp1_rsz_config_regs() functions use a v4l2_rect to pass frame sizes, leaving the top and left members unused and uninitialized. Use v4l2_area instead. Signed-off-by: Laurent Pinchart Reviewed-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c index 26f9c16ccc3e8..8700be7d19aa8 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c @@ -208,8 +208,8 @@ static void rkisp1_rsz_disable(struct rkisp1_resizer *rsz, static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz, const struct v4l2_rect *sink_y, const struct v4l2_rect *sink_c, - const struct v4l2_rect *src_y, - const struct v4l2_rect *src_c, + const struct v4l2_area *src_y, + const struct v4l2_area *src_c, enum rkisp1_shadow_regs_when when) { u32 ratio, rsz_ctrl = 0; @@ -272,7 +272,8 @@ static void rkisp1_rsz_config(struct rkisp1_resizer *rsz, const struct rkisp1_rsz_yuv_mbus_info *sink_yuv_info, *src_yuv_info; const struct v4l2_mbus_framefmt *src_fmt, *sink_fmt; const struct v4l2_rect *sink_crop; - struct v4l2_rect sink_y, sink_c, src_y, src_c; + struct v4l2_rect sink_y, sink_c; + struct v4l2_area src_y, src_c; sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, RKISP1_RSZ_PAD_SINK); -- GitLab From 1126d89f8f54a13e7c5cbee24c414603ee794f10 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 23 Sep 2023 22:49:06 +0300 Subject: [PATCH 0560/1451] media: rkisp1: resizer: Drop unneeded local variable The sink_y local variable in rkisp1_rsz_config() stores a copy of the sink_crop crop rectangle. Drop it, and rename sink_crop to sink_y. Signed-off-by: Laurent Pinchart Reviewed-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../platform/rockchip/rkisp1/rkisp1-resizer.c | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c index 8700be7d19aa8..1741ada7032b1 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c @@ -271,14 +271,12 @@ static void rkisp1_rsz_config(struct rkisp1_resizer *rsz, { const struct rkisp1_rsz_yuv_mbus_info *sink_yuv_info, *src_yuv_info; const struct v4l2_mbus_framefmt *src_fmt, *sink_fmt; - const struct v4l2_rect *sink_crop; - struct v4l2_rect sink_y, sink_c; + const struct v4l2_rect *sink_y; struct v4l2_area src_y, src_c; + struct v4l2_rect sink_c; sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, RKISP1_RSZ_PAD_SINK); - sink_crop = v4l2_subdev_get_pad_crop(&rsz->sd, sd_state, - RKISP1_RSZ_PAD_SINK); src_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, RKISP1_RSZ_PAD_SRC); @@ -294,14 +292,14 @@ static void rkisp1_rsz_config(struct rkisp1_resizer *rsz, return; } - sink_y.width = sink_crop->width; - sink_y.height = sink_crop->height; + sink_y = v4l2_subdev_get_pad_crop(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SINK); + sink_c.width = sink_y->width / sink_yuv_info->hdiv; + sink_c.height = sink_y->height / sink_yuv_info->vdiv; + src_y.width = src_fmt->width; src_y.height = src_fmt->height; - sink_c.width = sink_y.width / sink_yuv_info->hdiv; - sink_c.height = sink_y.height / sink_yuv_info->vdiv; - /* * The resizer is used not only to change the dimensions of the frame * but also to change the scale for YUV formats, @@ -317,13 +315,13 @@ static void rkisp1_rsz_config(struct rkisp1_resizer *rsz, } dev_dbg(rsz->rkisp1->dev, "stream %d rsz/scale: %dx%d -> %dx%d\n", - rsz->id, sink_crop->width, sink_crop->height, + rsz->id, sink_y->width, sink_y->height, src_fmt->width, src_fmt->height); dev_dbg(rsz->rkisp1->dev, "chroma scaling %dx%d -> %dx%d\n", sink_c.width, sink_c.height, src_c.width, src_c.height); /* set values in the hw */ - rkisp1_rsz_config_regs(rsz, &sink_y, &sink_c, &src_y, &src_c, when); + rkisp1_rsz_config_regs(rsz, sink_y, &sink_c, &src_y, &src_c, when); } /* ---------------------------------------------------------------------------- -- GitLab From e09b03627643e1f40bfaacf29be0de7df1c8c05d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 25 Sep 2023 03:20:08 +0300 Subject: [PATCH 0561/1451] media: rkisp1: resizer: Improve debug message when configuring resizer The debug messages that show the resizer configuration are only printed if the driver enables the resizer. This prevents checking the resizer configuration when the driver believes it should be disabled. Fix it by moving the dev_dbg() statements earlier. Also, combine the two debug prints into a single one to gather all the information in one place, which makes reading the log easier. While at it, use %u instead of %d to print unsigned values. Signed-off-by: Laurent Pinchart Reviewed-by: Sakari Ailus Signed-off-by: Hans Verkuil --- .../media/platform/rockchip/rkisp1/rkisp1-resizer.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c index 1741ada7032b1..92ae2d2e0f124 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c @@ -309,17 +309,17 @@ static void rkisp1_rsz_config(struct rkisp1_resizer *rsz, src_c.width = src_y.width / src_yuv_info->hdiv; src_c.height = src_y.height / src_yuv_info->vdiv; + dev_dbg(rsz->rkisp1->dev, + "stream %u rsz/scale: Y %ux%u -> %ux%u, CbCr %ux%u -> %ux%u\n", + rsz->id, sink_y->width, sink_y->height, + src_fmt->width, src_fmt->height, + sink_c.width, sink_c.height, src_c.width, src_c.height); + if (sink_c.width == src_c.width && sink_c.height == src_c.height) { rkisp1_rsz_disable(rsz, when); return; } - dev_dbg(rsz->rkisp1->dev, "stream %d rsz/scale: %dx%d -> %dx%d\n", - rsz->id, sink_y->width, sink_y->height, - src_fmt->width, src_fmt->height); - dev_dbg(rsz->rkisp1->dev, "chroma scaling %dx%d -> %dx%d\n", - sink_c.width, sink_c.height, src_c.width, src_c.height); - /* set values in the hw */ rkisp1_rsz_config_regs(rsz, sink_y, &sink_c, &src_y, &src_c, when); } -- GitLab From d13fabf08d7cf4439d8f2f477458c7c353aebe87 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 23 Sep 2023 22:49:06 +0300 Subject: [PATCH 0562/1451] media: rkisp1: resizer: Fix resizer disable check when starting stream The resizer is used to scale the image, but also to change the subsampling of YUV formats. Both the luma and chroma dimensions need to be taken into account to decide whether or not to enable the resizer. The current implementation disables the resizer if the chroma vertical size isn't changed, which would be the case when scaling up by a factor of 2 vertically while at the same time converting from YUV 4:2:2 to 4:2:0. Fix it by checking the luma sizes too. While at it, reflow and clarify comments in the function. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- .../platform/rockchip/rkisp1/rkisp1-resizer.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c index 92ae2d2e0f124..28ecc7347d543 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c @@ -284,8 +284,8 @@ static void rkisp1_rsz_config(struct rkisp1_resizer *rsz, src_yuv_info = rkisp1_rsz_get_yuv_mbus_info(src_fmt->code); /* - * The resizer only works on yuv formats, - * so return if it is bayer format. + * The resizer only works on yuv formats, so return if it is bayer + * format. */ if (!sink_yuv_info) { rkisp1_rsz_disable(rsz, when); @@ -299,15 +299,15 @@ static void rkisp1_rsz_config(struct rkisp1_resizer *rsz, src_y.width = src_fmt->width; src_y.height = src_fmt->height; + src_c.width = src_y.width / src_yuv_info->hdiv; + src_c.height = src_y.height / src_yuv_info->vdiv; /* * The resizer is used not only to change the dimensions of the frame - * but also to change the scale for YUV formats, - * (4:2:2 -> 4:2:0 for example). So the width/height of the CbCr - * streams should be set according to the media bus format in the src pad. + * but also to change the subsampling for YUV formats (for instance + * converting from 4:2:2 to 4:2:0). Check both the luma and chroma + * dimensions to decide whether or not to enable the resizer. */ - src_c.width = src_y.width / src_yuv_info->hdiv; - src_c.height = src_y.height / src_yuv_info->vdiv; dev_dbg(rsz->rkisp1->dev, "stream %u rsz/scale: Y %ux%u -> %ux%u, CbCr %ux%u -> %ux%u\n", @@ -315,12 +315,13 @@ static void rkisp1_rsz_config(struct rkisp1_resizer *rsz, src_fmt->width, src_fmt->height, sink_c.width, sink_c.height, src_c.width, src_c.height); - if (sink_c.width == src_c.width && sink_c.height == src_c.height) { + if (sink_y->width == src_y.width && sink_y->height == src_y.height && + sink_c.width == src_c.width && sink_c.height == src_c.height) { rkisp1_rsz_disable(rsz, when); return; } - /* set values in the hw */ + /* Set values in the hardware. */ rkisp1_rsz_config_regs(rsz, sink_y, &sink_c, &src_y, &src_c, when); } -- GitLab From b925fb423d3c9aa5cf24bd5e4953649fcf271245 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 6 Oct 2023 12:08:43 +0200 Subject: [PATCH 0563/1451] media: i2c: adp1653: don't reuse the same node pointer The child device_node pointer was used for two different children. This confused smatch, causing this warning: drivers/media/i2c/adp1653.c:444 adp1653_of_init() warn: missing unwind goto? Use two different pointers, one for each child node, and add separate goto labels for each node as well. This also improves error logging since it will now state for which node the property was missing. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus [hverkuil: fix typo: childs -> children] --- drivers/media/i2c/adp1653.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c index 98ca417b8004c..5ace7b5804d44 100644 --- a/drivers/media/i2c/adp1653.c +++ b/drivers/media/i2c/adp1653.c @@ -411,43 +411,44 @@ static int adp1653_of_init(struct i2c_client *client, struct device_node *node) { struct adp1653_platform_data *pd; - struct device_node *child; + struct device_node *node_indicator = NULL; + struct device_node *node_flash; pd = devm_kzalloc(&client->dev, sizeof(*pd), GFP_KERNEL); if (!pd) return -ENOMEM; flash->platform_data = pd; - child = of_get_child_by_name(node, "flash"); - if (!child) + node_flash = of_get_child_by_name(node, "flash"); + if (!node_flash) return -EINVAL; - if (of_property_read_u32(child, "flash-timeout-us", + if (of_property_read_u32(node_flash, "flash-timeout-us", &pd->max_flash_timeout)) goto err; - if (of_property_read_u32(child, "flash-max-microamp", + if (of_property_read_u32(node_flash, "flash-max-microamp", &pd->max_flash_intensity)) goto err; pd->max_flash_intensity /= 1000; - if (of_property_read_u32(child, "led-max-microamp", + if (of_property_read_u32(node_flash, "led-max-microamp", &pd->max_torch_intensity)) goto err; pd->max_torch_intensity /= 1000; - of_node_put(child); - child = of_get_child_by_name(node, "indicator"); - if (!child) - return -EINVAL; + node_indicator = of_get_child_by_name(node, "indicator"); + if (!node_indicator) + goto err; - if (of_property_read_u32(child, "led-max-microamp", + if (of_property_read_u32(node_indicator, "led-max-microamp", &pd->max_indicator_intensity)) goto err; - of_node_put(child); + of_node_put(node_flash); + of_node_put(node_indicator); pd->enable_gpio = devm_gpiod_get(&client->dev, "enable", GPIOD_OUT_LOW); if (IS_ERR(pd->enable_gpio)) { @@ -458,7 +459,8 @@ static int adp1653_of_init(struct i2c_client *client, return 0; err: dev_err(&client->dev, "Required property not found\n"); - of_node_put(child); + of_node_put(node_flash); + of_node_put(node_indicator); return -EINVAL; } -- GitLab From 51b74c09ac8c5862007fc2bf0d465529d06dd446 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 6 Oct 2023 12:08:47 +0200 Subject: [PATCH 0564/1451] media: qcom: venus: fix incorrect return value 'pd' can be NULL, and in that case it shouldn't be passed to PTR_ERR. Fixes a smatch warning: drivers/media/platform/qcom/venus/pm_helpers.c:873 vcodec_domains_get() warn: passing zero to 'PTR_ERR' Signed-off-by: Hans Verkuil Reviewed-by: Bryan O'Donoghue --- drivers/media/platform/qcom/venus/pm_helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index 48c9084bb4dba..a1b127caa90a7 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -870,7 +870,7 @@ static int vcodec_domains_get(struct venus_core *core) pd = dev_pm_domain_attach_by_name(dev, res->vcodec_pmdomains[i]); if (IS_ERR_OR_NULL(pd)) - return PTR_ERR(pd) ? : -ENODATA; + return pd ? PTR_ERR(pd) : -ENODATA; core->pmdomains[i] = pd; } -- GitLab From 270a1470408e44619a55be1079254bf2ba0567fb Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Mon, 25 Sep 2023 19:42:48 -0400 Subject: [PATCH 0565/1451] iommu/arm-smmu-qcom: Add SDM670 MDSS compatible Add the compatible for the MDSS client on the Snapdragon 670 so it can be properly configured by the IOMMU driver. Otherwise, there is an unhandled context fault. Signed-off-by: Richard Acayan Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230925234246.900351-3-mailingradian@gmail.com Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c index 7f52ac67495fd..8290494bc7eaa 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c @@ -251,6 +251,7 @@ static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = { { .compatible = "qcom,sc7280-mss-pil" }, { .compatible = "qcom,sc8180x-mdss" }, { .compatible = "qcom,sc8280xp-mdss" }, + { .compatible = "qcom,sdm670-mdss" }, { .compatible = "qcom,sdm845-mdss" }, { .compatible = "qcom,sdm845-mss-pil" }, { .compatible = "qcom,sm6350-mdss" }, -- GitLab From c53cdc02915a380b69c9db9e59e86b3a98415a3d Mon Sep 17 00:00:00 2001 From: Danila Tikhonov Date: Wed, 13 Sep 2023 21:45:24 +0300 Subject: [PATCH 0566/1451] dt-bindings: arm-smmu: Add SM7150 GPU SMMUv2 SM7150 has a qcom,smmu-v2-style SMMU just for Adreno and friends. Document it. Signed-off-by: Danila Tikhonov Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230913184526.20016-2-danila@jiaxyga.com Signed-off-by: Will Deacon --- Documentation/devicetree/bindings/iommu/arm,smmu.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml index b1b2cf81b42fc..aa9e1c0895a50 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml @@ -110,6 +110,7 @@ properties: - qcom,sdm630-smmu-v2 - qcom,sdm845-smmu-v2 - qcom,sm6350-smmu-v2 + - qcom,sm7150-smmu-v2 - const: qcom,adreno-smmu - const: qcom,smmu-v2 - description: Qcom Adreno GPUs on Google Cheza platform @@ -409,6 +410,7 @@ allOf: contains: enum: - qcom,sm6350-smmu-v2 + - qcom,sm7150-smmu-v2 - qcom,sm8150-smmu-500 - qcom,sm8250-smmu-500 then: -- GitLab From 70c613602b55d7011ccc4883ab5c0095db307db7 Mon Sep 17 00:00:00 2001 From: Danila Tikhonov Date: Wed, 13 Sep 2023 21:45:25 +0300 Subject: [PATCH 0567/1451] iommu/arm-smmu-qcom: Add SM7150 SMMUv2 SM7150 uses a qcom,smmu-v2-style SMMU just for Adreno and friends. Add a compatible for it. Signed-off-by: Danila Tikhonov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230913184526.20016-3-danila@jiaxyga.com Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c index 8290494bc7eaa..549ae4dba3a68 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c @@ -533,6 +533,7 @@ static const struct of_device_id __maybe_unused qcom_smmu_impl_of_match[] = { { .compatible = "qcom,sm6350-smmu-500", .data = &qcom_smmu_500_impl0_data }, { .compatible = "qcom,sm6375-smmu-v2", .data = &qcom_smmu_v2_data }, { .compatible = "qcom,sm6375-smmu-500", .data = &qcom_smmu_500_impl0_data }, + { .compatible = "qcom,sm7150-smmu-v2", .data = &qcom_smmu_v2_data }, { .compatible = "qcom,sm8150-smmu-500", .data = &qcom_smmu_500_impl0_data }, { .compatible = "qcom,sm8250-smmu-500", .data = &qcom_smmu_500_impl0_data }, { .compatible = "qcom,sm8350-smmu-500", .data = &qcom_smmu_500_impl0_data }, -- GitLab From 987a878e09c6c22b9c1a517900bd94d5ed0cc459 Mon Sep 17 00:00:00 2001 From: Michael Shavit Date: Fri, 15 Sep 2023 21:17:32 +0800 Subject: [PATCH 0568/1451] iommu/arm-smmu-v3: Move ctx_desc out of s1_cfg arm_smmu_s1_cfg (and by extension arm_smmu_domain) owns both a CD table and the CD inserted into that table's non-pasid CD entry. This limits arm_smmu_domain's ability to represent non-pasid domains, where multiple domains need to be inserted into a common CD table. Rather than describing an STE entry (which may have multiple domains installed into it with PASID), a domain should describe a single CD entry instead. This is precisely the role of arm_smmu_ctx_desc. A subsequent commit will also move the CD table outside of arm_smmu_domain. Reviewed-by: Jason Gunthorpe Reviewed-by: Nicolin Chen Signed-off-by: Michael Shavit Tested-by: Nicolin Chen Link: https://lore.kernel.org/r/20230915211705.v8.1.I67ab103c18d882aedc8a08985af1fba70bca084e@changeid Signed-off-by: Will Deacon --- .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 2 +- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 23 ++++++++++--------- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 6 +++-- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c index 8a16cd3ef487c..9b27fffe2ab95 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c @@ -62,7 +62,7 @@ arm_smmu_share_asid(struct mm_struct *mm, u16 asid) return cd; } - smmu_domain = container_of(cd, struct arm_smmu_domain, s1_cfg.cd); + smmu_domain = container_of(cd, struct arm_smmu_domain, cd); smmu = smmu_domain->smmu; ret = xa_alloc(&arm_smmu_asid_xa, &new_asid, cd, diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index bd0a596f9863a..b10333d44f9d6 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -1869,7 +1869,7 @@ static void arm_smmu_tlb_inv_context(void *cookie) * careful, 007. */ if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) { - arm_smmu_tlb_inv_asid(smmu, smmu_domain->s1_cfg.cd.asid); + arm_smmu_tlb_inv_asid(smmu, smmu_domain->cd.asid); } else { cmd.opcode = CMDQ_OP_TLBI_S12_VMALL; cmd.tlbi.vmid = smmu_domain->s2_cfg.vmid; @@ -1962,7 +1962,7 @@ static void arm_smmu_tlb_inv_range_domain(unsigned long iova, size_t size, if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) { cmd.opcode = smmu_domain->smmu->features & ARM_SMMU_FEAT_E2H ? CMDQ_OP_TLBI_EL2_VA : CMDQ_OP_TLBI_NH_VA; - cmd.tlbi.asid = smmu_domain->s1_cfg.cd.asid; + cmd.tlbi.asid = smmu_domain->cd.asid; } else { cmd.opcode = CMDQ_OP_TLBI_S2_IPA; cmd.tlbi.vmid = smmu_domain->s2_cfg.vmid; @@ -2075,7 +2075,7 @@ static void arm_smmu_domain_free(struct iommu_domain *domain) mutex_lock(&arm_smmu_asid_lock); if (cfg->cdcfg.cdtab) arm_smmu_free_cd_tables(smmu_domain); - arm_smmu_free_asid(&cfg->cd); + arm_smmu_free_asid(&smmu_domain->cd); mutex_unlock(&arm_smmu_asid_lock); } else { struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg; @@ -2094,13 +2094,14 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, u32 asid; struct arm_smmu_device *smmu = smmu_domain->smmu; struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg; + struct arm_smmu_ctx_desc *cd = &smmu_domain->cd; typeof(&pgtbl_cfg->arm_lpae_s1_cfg.tcr) tcr = &pgtbl_cfg->arm_lpae_s1_cfg.tcr; - refcount_set(&cfg->cd.refs, 1); + refcount_set(&cd->refs, 1); /* Prevent SVA from modifying the ASID until it is written to the CD */ mutex_lock(&arm_smmu_asid_lock); - ret = xa_alloc(&arm_smmu_asid_xa, &asid, &cfg->cd, + ret = xa_alloc(&arm_smmu_asid_xa, &asid, cd, XA_LIMIT(1, (1 << smmu->asid_bits) - 1), GFP_KERNEL); if (ret) goto out_unlock; @@ -2113,23 +2114,23 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, if (ret) goto out_free_asid; - cfg->cd.asid = (u16)asid; - cfg->cd.ttbr = pgtbl_cfg->arm_lpae_s1_cfg.ttbr; - cfg->cd.tcr = FIELD_PREP(CTXDESC_CD_0_TCR_T0SZ, tcr->tsz) | + cd->asid = (u16)asid; + cd->ttbr = pgtbl_cfg->arm_lpae_s1_cfg.ttbr; + cd->tcr = FIELD_PREP(CTXDESC_CD_0_TCR_T0SZ, tcr->tsz) | FIELD_PREP(CTXDESC_CD_0_TCR_TG0, tcr->tg) | FIELD_PREP(CTXDESC_CD_0_TCR_IRGN0, tcr->irgn) | FIELD_PREP(CTXDESC_CD_0_TCR_ORGN0, tcr->orgn) | FIELD_PREP(CTXDESC_CD_0_TCR_SH0, tcr->sh) | FIELD_PREP(CTXDESC_CD_0_TCR_IPS, tcr->ips) | CTXDESC_CD_0_TCR_EPD1 | CTXDESC_CD_0_AA64; - cfg->cd.mair = pgtbl_cfg->arm_lpae_s1_cfg.mair; + cd->mair = pgtbl_cfg->arm_lpae_s1_cfg.mair; /* * Note that this will end up calling arm_smmu_sync_cd() before * the master has been added to the devices list for this domain. * This isn't an issue because the STE hasn't been installed yet. */ - ret = arm_smmu_write_ctx_desc(smmu_domain, IOMMU_NO_PASID, &cfg->cd); + ret = arm_smmu_write_ctx_desc(smmu_domain, IOMMU_NO_PASID, cd); if (ret) goto out_free_cd_tables; @@ -2139,7 +2140,7 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, out_free_cd_tables: arm_smmu_free_cd_tables(smmu_domain); out_free_asid: - arm_smmu_free_asid(&cfg->cd); + arm_smmu_free_asid(cd); out_unlock: mutex_unlock(&arm_smmu_asid_lock); return ret; diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h index 9915850dd4dbf..9389780db1f34 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h @@ -599,7 +599,6 @@ struct arm_smmu_ctx_desc_cfg { struct arm_smmu_s1_cfg { struct arm_smmu_ctx_desc_cfg cdcfg; - struct arm_smmu_ctx_desc cd; u8 s1fmt; u8 s1cdmax; }; @@ -724,7 +723,10 @@ struct arm_smmu_domain { enum arm_smmu_domain_stage stage; union { - struct arm_smmu_s1_cfg s1_cfg; + struct { + struct arm_smmu_ctx_desc cd; + struct arm_smmu_s1_cfg s1_cfg; + }; struct arm_smmu_s2_cfg s2_cfg; }; -- GitLab From 1f8588834016ad9d07880b0055d6583dc4014099 Mon Sep 17 00:00:00 2001 From: Michael Shavit Date: Fri, 15 Sep 2023 21:17:33 +0800 Subject: [PATCH 0569/1451] iommu/arm-smmu-v3: Replace s1_cfg with cdtab_cfg Remove struct arm_smmu_s1_cfg. This is really just a CD table with a bit of extra information. Move other attributes of the CD table that were held there into the existing CD table structure, struct arm_smmu_ctx_desc_cfg, and replace all usages of arm_smmu_s1_cfg with arm_smmu_ctx_desc_cfg. For clarity, use the name "cd_table" for the variables pointing to arm_smmu_ctx_desc_cfg in the new code instead of cdcfg. A later patch will make this fully consistent. Reviewed-by: Jason Gunthorpe Reviewed-by: Nicolin Chen Signed-off-by: Michael Shavit Tested-by: Nicolin Chen Link: https://lore.kernel.org/r/20230915211705.v8.2.I1ef1ed19d7786c8176a0d05820c869e650c8d68f@changeid Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 41 ++++++++++----------- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 7 +--- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index b10333d44f9d6..223a414e877b6 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -1033,9 +1033,9 @@ static __le64 *arm_smmu_get_cd_ptr(struct arm_smmu_domain *smmu_domain, unsigned int idx; struct arm_smmu_l1_ctx_desc *l1_desc; struct arm_smmu_device *smmu = smmu_domain->smmu; - struct arm_smmu_ctx_desc_cfg *cdcfg = &smmu_domain->s1_cfg.cdcfg; + struct arm_smmu_ctx_desc_cfg *cdcfg = &smmu_domain->cd_table; - if (smmu_domain->s1_cfg.s1fmt == STRTAB_STE_0_S1FMT_LINEAR) + if (cdcfg->s1fmt == STRTAB_STE_0_S1FMT_LINEAR) return cdcfg->cdtab + ssid * CTXDESC_CD_DWORDS; idx = ssid >> CTXDESC_SPLIT; @@ -1071,7 +1071,7 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid, bool cd_live; __le64 *cdptr; - if (WARN_ON(ssid >= (1 << smmu_domain->s1_cfg.s1cdmax))) + if (WARN_ON(ssid >= (1 << smmu_domain->cd_table.s1cdmax))) return -E2BIG; cdptr = arm_smmu_get_cd_ptr(smmu_domain, ssid); @@ -1138,19 +1138,18 @@ static int arm_smmu_alloc_cd_tables(struct arm_smmu_domain *smmu_domain) size_t l1size; size_t max_contexts; struct arm_smmu_device *smmu = smmu_domain->smmu; - struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg; - struct arm_smmu_ctx_desc_cfg *cdcfg = &cfg->cdcfg; + struct arm_smmu_ctx_desc_cfg *cdcfg = &smmu_domain->cd_table; - max_contexts = 1 << cfg->s1cdmax; + max_contexts = 1 << cdcfg->s1cdmax; if (!(smmu->features & ARM_SMMU_FEAT_2_LVL_CDTAB) || max_contexts <= CTXDESC_L2_ENTRIES) { - cfg->s1fmt = STRTAB_STE_0_S1FMT_LINEAR; + cdcfg->s1fmt = STRTAB_STE_0_S1FMT_LINEAR; cdcfg->num_l1_ents = max_contexts; l1size = max_contexts * (CTXDESC_CD_DWORDS << 3); } else { - cfg->s1fmt = STRTAB_STE_0_S1FMT_64K_L2; + cdcfg->s1fmt = STRTAB_STE_0_S1FMT_64K_L2; cdcfg->num_l1_ents = DIV_ROUND_UP(max_contexts, CTXDESC_L2_ENTRIES); @@ -1186,7 +1185,7 @@ static void arm_smmu_free_cd_tables(struct arm_smmu_domain *smmu_domain) int i; size_t size, l1size; struct arm_smmu_device *smmu = smmu_domain->smmu; - struct arm_smmu_ctx_desc_cfg *cdcfg = &smmu_domain->s1_cfg.cdcfg; + struct arm_smmu_ctx_desc_cfg *cdcfg = &smmu_domain->cd_table; if (cdcfg->l1_desc) { size = CTXDESC_L2_ENTRIES * (CTXDESC_CD_DWORDS << 3); @@ -1276,7 +1275,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid, u64 val = le64_to_cpu(dst[0]); bool ste_live = false; struct arm_smmu_device *smmu = NULL; - struct arm_smmu_s1_cfg *s1_cfg = NULL; + struct arm_smmu_ctx_desc_cfg *cd_table = NULL; struct arm_smmu_s2_cfg *s2_cfg = NULL; struct arm_smmu_domain *smmu_domain = NULL; struct arm_smmu_cmdq_ent prefetch_cmd = { @@ -1294,7 +1293,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid, if (smmu_domain) { switch (smmu_domain->stage) { case ARM_SMMU_DOMAIN_S1: - s1_cfg = &smmu_domain->s1_cfg; + cd_table = &smmu_domain->cd_table; break; case ARM_SMMU_DOMAIN_S2: case ARM_SMMU_DOMAIN_NESTED: @@ -1325,7 +1324,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid, val = STRTAB_STE_0_V; /* Bypass/fault */ - if (!smmu_domain || !(s1_cfg || s2_cfg)) { + if (!smmu_domain || !(cd_table || s2_cfg)) { if (!smmu_domain && disable_bypass) val |= FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_ABORT); else @@ -1344,7 +1343,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid, return; } - if (s1_cfg) { + if (cd_table) { u64 strw = smmu->features & ARM_SMMU_FEAT_E2H ? STRTAB_STE_1_STRW_EL2 : STRTAB_STE_1_STRW_NSEL1; @@ -1360,10 +1359,10 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid, !master->stall_enabled) dst[1] |= cpu_to_le64(STRTAB_STE_1_S1STALLD); - val |= (s1_cfg->cdcfg.cdtab_dma & STRTAB_STE_0_S1CTXPTR_MASK) | + val |= (cd_table->cdtab_dma & STRTAB_STE_0_S1CTXPTR_MASK) | FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_S1_TRANS) | - FIELD_PREP(STRTAB_STE_0_S1CDMAX, s1_cfg->s1cdmax) | - FIELD_PREP(STRTAB_STE_0_S1FMT, s1_cfg->s1fmt); + FIELD_PREP(STRTAB_STE_0_S1CDMAX, cd_table->s1cdmax) | + FIELD_PREP(STRTAB_STE_0_S1FMT, cd_table->s1fmt); } if (s2_cfg) { @@ -2069,11 +2068,11 @@ static void arm_smmu_domain_free(struct iommu_domain *domain) /* Free the CD and ASID, if we allocated them */ if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) { - struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg; + struct arm_smmu_ctx_desc_cfg *cd_table = &smmu_domain->cd_table; /* Prevent SVA from touching the CD while we're freeing it */ mutex_lock(&arm_smmu_asid_lock); - if (cfg->cdcfg.cdtab) + if (cd_table->cdtab) arm_smmu_free_cd_tables(smmu_domain); arm_smmu_free_asid(&smmu_domain->cd); mutex_unlock(&arm_smmu_asid_lock); @@ -2093,7 +2092,7 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, int ret; u32 asid; struct arm_smmu_device *smmu = smmu_domain->smmu; - struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg; + struct arm_smmu_ctx_desc_cfg *cd_table = &smmu_domain->cd_table; struct arm_smmu_ctx_desc *cd = &smmu_domain->cd; typeof(&pgtbl_cfg->arm_lpae_s1_cfg.tcr) tcr = &pgtbl_cfg->arm_lpae_s1_cfg.tcr; @@ -2106,7 +2105,7 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, if (ret) goto out_unlock; - cfg->s1cdmax = master->ssid_bits; + cd_table->s1cdmax = master->ssid_bits; smmu_domain->stall_enabled = master->stall_enabled; @@ -2446,7 +2445,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) ret = -EINVAL; goto out_unlock; } else if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1 && - master->ssid_bits != smmu_domain->s1_cfg.s1cdmax) { + master->ssid_bits != smmu_domain->cd_table.s1cdmax) { ret = -EINVAL; goto out_unlock; } else if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1 && diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h index 9389780db1f34..def1de62a59c6 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h @@ -595,11 +595,8 @@ struct arm_smmu_ctx_desc_cfg { dma_addr_t cdtab_dma; struct arm_smmu_l1_ctx_desc *l1_desc; unsigned int num_l1_ents; -}; - -struct arm_smmu_s1_cfg { - struct arm_smmu_ctx_desc_cfg cdcfg; u8 s1fmt; + /* log2 of the maximum number of CDs supported by this table */ u8 s1cdmax; }; @@ -725,7 +722,7 @@ struct arm_smmu_domain { union { struct { struct arm_smmu_ctx_desc cd; - struct arm_smmu_s1_cfg s1_cfg; + struct arm_smmu_ctx_desc_cfg cd_table; }; struct arm_smmu_s2_cfg s2_cfg; }; -- GitLab From e3aad74c51a7012233ebe249c8ed86bb01c4a3f0 Mon Sep 17 00:00:00 2001 From: Michael Shavit Date: Fri, 15 Sep 2023 21:17:34 +0800 Subject: [PATCH 0570/1451] iommu/arm-smmu-v3: Encapsulate ctx_desc_cfg init in alloc_cd_tables This is slighlty cleaner: arm_smmu_ctx_desc_cfg is initialized in a single function instead of having pieces set ahead-of time by its caller. Reviewed-by: Jason Gunthorpe Reviewed-by: Nicolin Chen Signed-off-by: Michael Shavit Tested-by: Nicolin Chen Link: https://lore.kernel.org/r/20230915211705.v8.3.I875254464d044a8ce8b3a2ad6beb655a4a006456@changeid Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index 223a414e877b6..cd6b3fca04815 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -1132,7 +1132,8 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid, return 0; } -static int arm_smmu_alloc_cd_tables(struct arm_smmu_domain *smmu_domain) +static int arm_smmu_alloc_cd_tables(struct arm_smmu_domain *smmu_domain, + struct arm_smmu_master *master) { int ret; size_t l1size; @@ -1140,6 +1141,7 @@ static int arm_smmu_alloc_cd_tables(struct arm_smmu_domain *smmu_domain) struct arm_smmu_device *smmu = smmu_domain->smmu; struct arm_smmu_ctx_desc_cfg *cdcfg = &smmu_domain->cd_table; + cdcfg->s1cdmax = master->ssid_bits; max_contexts = 1 << cdcfg->s1cdmax; if (!(smmu->features & ARM_SMMU_FEAT_2_LVL_CDTAB) || @@ -2092,7 +2094,6 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, int ret; u32 asid; struct arm_smmu_device *smmu = smmu_domain->smmu; - struct arm_smmu_ctx_desc_cfg *cd_table = &smmu_domain->cd_table; struct arm_smmu_ctx_desc *cd = &smmu_domain->cd; typeof(&pgtbl_cfg->arm_lpae_s1_cfg.tcr) tcr = &pgtbl_cfg->arm_lpae_s1_cfg.tcr; @@ -2105,11 +2106,9 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, if (ret) goto out_unlock; - cd_table->s1cdmax = master->ssid_bits; - smmu_domain->stall_enabled = master->stall_enabled; - ret = arm_smmu_alloc_cd_tables(smmu_domain); + ret = arm_smmu_alloc_cd_tables(smmu_domain, master); if (ret) goto out_free_asid; -- GitLab From 1228cc509fc6bf7b10f0c5e202086979e4bbd43a Mon Sep 17 00:00:00 2001 From: Michael Shavit Date: Fri, 15 Sep 2023 21:17:35 +0800 Subject: [PATCH 0571/1451] iommu/arm-smmu-v3: move stall_enabled to the cd table A domain can be attached to multiple masters with different master->stall_enabled values. The stall bit of a CD entry should follow master->stall_enabled and has an inverse relationship with the STE.S1STALLD bit. The stall_enabled bit does not depend on any property of the domain, so move it out of the arm_smmu_domain struct. Move it to the CD table struct so that it can fully describe how CD entries should be written to it. Reviewed-by: Jason Gunthorpe Reviewed-by: Nicolin Chen Signed-off-by: Michael Shavit Tested-by: Nicolin Chen Link: https://lore.kernel.org/r/20230915211705.v8.4.I5aa89c849228794a64146cfe86df21fb71629384@changeid Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 8 ++++---- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index cd6b3fca04815..39c2b0c451f30 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -1114,7 +1114,7 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid, FIELD_PREP(CTXDESC_CD_0_ASID, cd->asid) | CTXDESC_CD_0_V; - if (smmu_domain->stall_enabled) + if (smmu_domain->cd_table.stall_enabled) val |= CTXDESC_CD_0_S; } @@ -1141,6 +1141,7 @@ static int arm_smmu_alloc_cd_tables(struct arm_smmu_domain *smmu_domain, struct arm_smmu_device *smmu = smmu_domain->smmu; struct arm_smmu_ctx_desc_cfg *cdcfg = &smmu_domain->cd_table; + cdcfg->stall_enabled = master->stall_enabled; cdcfg->s1cdmax = master->ssid_bits; max_contexts = 1 << cdcfg->s1cdmax; @@ -2106,8 +2107,6 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, if (ret) goto out_unlock; - smmu_domain->stall_enabled = master->stall_enabled; - ret = arm_smmu_alloc_cd_tables(smmu_domain, master); if (ret) goto out_free_asid; @@ -2448,7 +2447,8 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) ret = -EINVAL; goto out_unlock; } else if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1 && - smmu_domain->stall_enabled != master->stall_enabled) { + smmu_domain->cd_table.stall_enabled != + master->stall_enabled) { ret = -EINVAL; goto out_unlock; } diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h index def1de62a59c6..287bef2d16aae 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h @@ -598,6 +598,8 @@ struct arm_smmu_ctx_desc_cfg { u8 s1fmt; /* log2 of the maximum number of CDs supported by this table */ u8 s1cdmax; + /* Whether CD entries in this table have the stall bit set. */ + u8 stall_enabled:1; }; struct arm_smmu_s2_cfg { @@ -715,7 +717,6 @@ struct arm_smmu_domain { struct mutex init_mutex; /* Protects smmu pointer */ struct io_pgtable_ops *pgtbl_ops; - bool stall_enabled; atomic_t nr_ats_masters; enum arm_smmu_domain_stage stage; -- GitLab From 24503148c545f08c10de73cc3a3779f1ee7a8fa0 Mon Sep 17 00:00:00 2001 From: Michael Shavit Date: Fri, 15 Sep 2023 21:17:36 +0800 Subject: [PATCH 0572/1451] iommu/arm-smmu-v3: Refactor write_ctx_desc Update arm_smmu_write_ctx_desc and downstream functions to operate on a master instead of an smmu domain. We expect arm_smmu_write_ctx_desc() to only be called to write a CD entry into a CD table owned by the master. Under the hood, arm_smmu_write_ctx_desc still fetches the CD table from the domain that is attached to the master, but a subsequent commit will move that table's ownership to the master. Note that this change isn't a nop refactor since SVA will call arm_smmu_write_ctx_desc in a loop for every master the domain is attached to despite the fact that they all share the same CD table. This loop may look weird but becomes necessary when the CD table becomes per-master in a subsequent commit. Reviewed-by: Jason Gunthorpe Reviewed-by: Nicolin Chen Signed-off-by: Michael Shavit Tested-by: Nicolin Chen Link: https://lore.kernel.org/r/20230915211705.v8.5.I219054a6cf538df5bb22f4ada2d9933155d6058c@changeid Signed-off-by: Will Deacon --- .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 39 +++++++++++++-- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 48 +++++++------------ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 2 +- 3 files changed, 54 insertions(+), 35 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c index 9b27fffe2ab95..df66fe43a9853 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c @@ -37,6 +37,25 @@ struct arm_smmu_bond { static DEFINE_MUTEX(sva_lock); +/* + * Write the CD to the CD tables for all masters that this domain is attached + * to. Note that this is only used to update existing CD entries in the target + * CD table, for which it's assumed that arm_smmu_write_ctx_desc can't fail. + */ +static void arm_smmu_update_ctx_desc_devices(struct arm_smmu_domain *smmu_domain, + int ssid, + struct arm_smmu_ctx_desc *cd) +{ + struct arm_smmu_master *master; + unsigned long flags; + + spin_lock_irqsave(&smmu_domain->devices_lock, flags); + list_for_each_entry(master, &smmu_domain->devices, domain_head) { + arm_smmu_write_ctx_desc(master, ssid, cd); + } + spin_unlock_irqrestore(&smmu_domain->devices_lock, flags); +} + /* * Check if the CPU ASID is available on the SMMU side. If a private context * descriptor is using it, try to replace it. @@ -80,7 +99,7 @@ arm_smmu_share_asid(struct mm_struct *mm, u16 asid) * be some overlap between use of both ASIDs, until we invalidate the * TLB. */ - arm_smmu_write_ctx_desc(smmu_domain, IOMMU_NO_PASID, cd); + arm_smmu_update_ctx_desc_devices(smmu_domain, IOMMU_NO_PASID, cd); /* Invalidate TLB entries previously associated with that context */ arm_smmu_tlb_inv_asid(smmu, asid); @@ -247,7 +266,7 @@ static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm) * DMA may still be running. Keep the cd valid to avoid C_BAD_CD events, * but disable translation. */ - arm_smmu_write_ctx_desc(smmu_domain, mm->pasid, &quiet_cd); + arm_smmu_update_ctx_desc_devices(smmu_domain, mm->pasid, &quiet_cd); arm_smmu_tlb_inv_asid(smmu_domain->smmu, smmu_mn->cd->asid); arm_smmu_atc_inv_domain(smmu_domain, mm->pasid, 0, 0); @@ -273,8 +292,10 @@ arm_smmu_mmu_notifier_get(struct arm_smmu_domain *smmu_domain, struct mm_struct *mm) { int ret; + unsigned long flags; struct arm_smmu_ctx_desc *cd; struct arm_smmu_mmu_notifier *smmu_mn; + struct arm_smmu_master *master; list_for_each_entry(smmu_mn, &smmu_domain->mmu_notifiers, list) { if (smmu_mn->mn.mm == mm) { @@ -304,7 +325,16 @@ arm_smmu_mmu_notifier_get(struct arm_smmu_domain *smmu_domain, goto err_free_cd; } - ret = arm_smmu_write_ctx_desc(smmu_domain, mm->pasid, cd); + spin_lock_irqsave(&smmu_domain->devices_lock, flags); + list_for_each_entry(master, &smmu_domain->devices, domain_head) { + ret = arm_smmu_write_ctx_desc(master, mm->pasid, cd); + if (ret) { + list_for_each_entry_from_reverse(master, &smmu_domain->devices, domain_head) + arm_smmu_write_ctx_desc(master, mm->pasid, NULL); + break; + } + } + spin_unlock_irqrestore(&smmu_domain->devices_lock, flags); if (ret) goto err_put_notifier; @@ -329,7 +359,8 @@ static void arm_smmu_mmu_notifier_put(struct arm_smmu_mmu_notifier *smmu_mn) return; list_del(&smmu_mn->list); - arm_smmu_write_ctx_desc(smmu_domain, mm->pasid, NULL); + + arm_smmu_update_ctx_desc_devices(smmu_domain, mm->pasid, NULL); /* * If we went through clear(), we've already invalidated, and no diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index 39c2b0c451f30..eacfa82b921ad 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -971,14 +971,12 @@ void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid) arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd); } -static void arm_smmu_sync_cd(struct arm_smmu_domain *smmu_domain, +static void arm_smmu_sync_cd(struct arm_smmu_master *master, int ssid, bool leaf) { size_t i; - unsigned long flags; - struct arm_smmu_master *master; struct arm_smmu_cmdq_batch cmds; - struct arm_smmu_device *smmu = smmu_domain->smmu; + struct arm_smmu_device *smmu = master->smmu; struct arm_smmu_cmdq_ent cmd = { .opcode = CMDQ_OP_CFGI_CD, .cfgi = { @@ -988,15 +986,10 @@ static void arm_smmu_sync_cd(struct arm_smmu_domain *smmu_domain, }; cmds.num = 0; - - spin_lock_irqsave(&smmu_domain->devices_lock, flags); - list_for_each_entry(master, &smmu_domain->devices, domain_head) { - for (i = 0; i < master->num_streams; i++) { - cmd.cfgi.sid = master->streams[i].id; - arm_smmu_cmdq_batch_add(smmu, &cmds, &cmd); - } + for (i = 0; i < master->num_streams; i++) { + cmd.cfgi.sid = master->streams[i].id; + arm_smmu_cmdq_batch_add(smmu, &cmds, &cmd); } - spin_unlock_irqrestore(&smmu_domain->devices_lock, flags); arm_smmu_cmdq_batch_submit(smmu, &cmds); } @@ -1026,14 +1019,13 @@ static void arm_smmu_write_cd_l1_desc(__le64 *dst, WRITE_ONCE(*dst, cpu_to_le64(val)); } -static __le64 *arm_smmu_get_cd_ptr(struct arm_smmu_domain *smmu_domain, - u32 ssid) +static __le64 *arm_smmu_get_cd_ptr(struct arm_smmu_master *master, u32 ssid) { __le64 *l1ptr; unsigned int idx; struct arm_smmu_l1_ctx_desc *l1_desc; - struct arm_smmu_device *smmu = smmu_domain->smmu; - struct arm_smmu_ctx_desc_cfg *cdcfg = &smmu_domain->cd_table; + struct arm_smmu_device *smmu = master->smmu; + struct arm_smmu_ctx_desc_cfg *cdcfg = &master->domain->cd_table; if (cdcfg->s1fmt == STRTAB_STE_0_S1FMT_LINEAR) return cdcfg->cdtab + ssid * CTXDESC_CD_DWORDS; @@ -1047,13 +1039,13 @@ static __le64 *arm_smmu_get_cd_ptr(struct arm_smmu_domain *smmu_domain, l1ptr = cdcfg->cdtab + idx * CTXDESC_L1_DESC_DWORDS; arm_smmu_write_cd_l1_desc(l1ptr, l1_desc); /* An invalid L1CD can be cached */ - arm_smmu_sync_cd(smmu_domain, ssid, false); + arm_smmu_sync_cd(master, ssid, false); } idx = ssid & (CTXDESC_L2_ENTRIES - 1); return l1_desc->l2ptr + idx * CTXDESC_CD_DWORDS; } -int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid, +int arm_smmu_write_ctx_desc(struct arm_smmu_master *master, int ssid, struct arm_smmu_ctx_desc *cd) { /* @@ -1070,11 +1062,12 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid, u64 val; bool cd_live; __le64 *cdptr; + struct arm_smmu_ctx_desc_cfg *cd_table = &master->domain->cd_table; - if (WARN_ON(ssid >= (1 << smmu_domain->cd_table.s1cdmax))) + if (WARN_ON(ssid >= (1 << cd_table->s1cdmax))) return -E2BIG; - cdptr = arm_smmu_get_cd_ptr(smmu_domain, ssid); + cdptr = arm_smmu_get_cd_ptr(master, ssid); if (!cdptr) return -ENOMEM; @@ -1102,7 +1095,7 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid, * order. Ensure that it observes valid values before reading * V=1. */ - arm_smmu_sync_cd(smmu_domain, ssid, true); + arm_smmu_sync_cd(master, ssid, true); val = cd->tcr | #ifdef __BIG_ENDIAN @@ -1114,7 +1107,7 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid, FIELD_PREP(CTXDESC_CD_0_ASID, cd->asid) | CTXDESC_CD_0_V; - if (smmu_domain->cd_table.stall_enabled) + if (cd_table->stall_enabled) val |= CTXDESC_CD_0_S; } @@ -1128,7 +1121,7 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid, * without first making the structure invalid. */ WRITE_ONCE(cdptr[0], cpu_to_le64(val)); - arm_smmu_sync_cd(smmu_domain, ssid, true); + arm_smmu_sync_cd(master, ssid, true); return 0; } @@ -1138,7 +1131,7 @@ static int arm_smmu_alloc_cd_tables(struct arm_smmu_domain *smmu_domain, int ret; size_t l1size; size_t max_contexts; - struct arm_smmu_device *smmu = smmu_domain->smmu; + struct arm_smmu_device *smmu = master->smmu; struct arm_smmu_ctx_desc_cfg *cdcfg = &smmu_domain->cd_table; cdcfg->stall_enabled = master->stall_enabled; @@ -2122,12 +2115,7 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, CTXDESC_CD_0_TCR_EPD1 | CTXDESC_CD_0_AA64; cd->mair = pgtbl_cfg->arm_lpae_s1_cfg.mair; - /* - * Note that this will end up calling arm_smmu_sync_cd() before - * the master has been added to the devices list for this domain. - * This isn't an issue because the STE hasn't been installed yet. - */ - ret = arm_smmu_write_ctx_desc(smmu_domain, IOMMU_NO_PASID, cd); + ret = arm_smmu_write_ctx_desc(master, IOMMU_NO_PASID, cd); if (ret) goto out_free_cd_tables; diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h index 287bef2d16aae..d2fc0a9793e54 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h @@ -745,7 +745,7 @@ extern struct xarray arm_smmu_asid_xa; extern struct mutex arm_smmu_asid_lock; extern struct arm_smmu_ctx_desc quiet_cd; -int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid, +int arm_smmu_write_ctx_desc(struct arm_smmu_master *smmu_master, int ssid, struct arm_smmu_ctx_desc *cd); void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid); void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid, -- GitLab From 10e4968cd511e3125cf62574aee950c4012c161a Mon Sep 17 00:00:00 2001 From: Michael Shavit Date: Fri, 15 Sep 2023 21:17:37 +0800 Subject: [PATCH 0573/1451] iommu/arm-smmu-v3: Move CD table to arm_smmu_master With this change, each master will now own its own CD table instead of sharing one with other masters attached to the same domain. Attaching a stage 1 domain installs CD entries into the master's CD table. SVA writes its CD entries into each master's CD table if the domain is shared across masters. Also add the device to the devices list before writing the CD to the table so that SVA will know that the CD needs to be re-written to this device's CD table as well if it decides to update the CD's ASID concurrently with this function. Tested-by: Nicolin Chen Reviewed-by: Jason Gunthorpe Signed-off-by: Michael Shavit Link: https://lore.kernel.org/r/20230915211705.v8.6.Ice063dcf87d1b777a72e008d9e3406d2bcf6d876@changeid Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 100 +++++++++++--------- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 7 +- 2 files changed, 58 insertions(+), 49 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index eacfa82b921ad..96f68161695e9 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -1025,7 +1025,7 @@ static __le64 *arm_smmu_get_cd_ptr(struct arm_smmu_master *master, u32 ssid) unsigned int idx; struct arm_smmu_l1_ctx_desc *l1_desc; struct arm_smmu_device *smmu = master->smmu; - struct arm_smmu_ctx_desc_cfg *cdcfg = &master->domain->cd_table; + struct arm_smmu_ctx_desc_cfg *cdcfg = &master->cd_table; if (cdcfg->s1fmt == STRTAB_STE_0_S1FMT_LINEAR) return cdcfg->cdtab + ssid * CTXDESC_CD_DWORDS; @@ -1062,7 +1062,7 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_master *master, int ssid, u64 val; bool cd_live; __le64 *cdptr; - struct arm_smmu_ctx_desc_cfg *cd_table = &master->domain->cd_table; + struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table; if (WARN_ON(ssid >= (1 << cd_table->s1cdmax))) return -E2BIG; @@ -1125,14 +1125,13 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_master *master, int ssid, return 0; } -static int arm_smmu_alloc_cd_tables(struct arm_smmu_domain *smmu_domain, - struct arm_smmu_master *master) +static int arm_smmu_alloc_cd_tables(struct arm_smmu_master *master) { int ret; size_t l1size; size_t max_contexts; struct arm_smmu_device *smmu = master->smmu; - struct arm_smmu_ctx_desc_cfg *cdcfg = &smmu_domain->cd_table; + struct arm_smmu_ctx_desc_cfg *cdcfg = &master->cd_table; cdcfg->stall_enabled = master->stall_enabled; cdcfg->s1cdmax = master->ssid_bits; @@ -1176,12 +1175,12 @@ static int arm_smmu_alloc_cd_tables(struct arm_smmu_domain *smmu_domain, return ret; } -static void arm_smmu_free_cd_tables(struct arm_smmu_domain *smmu_domain) +static void arm_smmu_free_cd_tables(struct arm_smmu_master *master) { int i; size_t size, l1size; - struct arm_smmu_device *smmu = smmu_domain->smmu; - struct arm_smmu_ctx_desc_cfg *cdcfg = &smmu_domain->cd_table; + struct arm_smmu_device *smmu = master->smmu; + struct arm_smmu_ctx_desc_cfg *cdcfg = &master->cd_table; if (cdcfg->l1_desc) { size = CTXDESC_L2_ENTRIES * (CTXDESC_CD_DWORDS << 3); @@ -1289,7 +1288,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid, if (smmu_domain) { switch (smmu_domain->stage) { case ARM_SMMU_DOMAIN_S1: - cd_table = &smmu_domain->cd_table; + cd_table = &master->cd_table; break; case ARM_SMMU_DOMAIN_S2: case ARM_SMMU_DOMAIN_NESTED: @@ -2062,14 +2061,10 @@ static void arm_smmu_domain_free(struct iommu_domain *domain) free_io_pgtable_ops(smmu_domain->pgtbl_ops); - /* Free the CD and ASID, if we allocated them */ + /* Free the ASID or VMID */ if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) { - struct arm_smmu_ctx_desc_cfg *cd_table = &smmu_domain->cd_table; - /* Prevent SVA from touching the CD while we're freeing it */ mutex_lock(&arm_smmu_asid_lock); - if (cd_table->cdtab) - arm_smmu_free_cd_tables(smmu_domain); arm_smmu_free_asid(&smmu_domain->cd); mutex_unlock(&arm_smmu_asid_lock); } else { @@ -2100,10 +2095,6 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, if (ret) goto out_unlock; - ret = arm_smmu_alloc_cd_tables(smmu_domain, master); - if (ret) - goto out_free_asid; - cd->asid = (u16)asid; cd->ttbr = pgtbl_cfg->arm_lpae_s1_cfg.ttbr; cd->tcr = FIELD_PREP(CTXDESC_CD_0_TCR_T0SZ, tcr->tsz) | @@ -2115,17 +2106,9 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, CTXDESC_CD_0_TCR_EPD1 | CTXDESC_CD_0_AA64; cd->mair = pgtbl_cfg->arm_lpae_s1_cfg.mair; - ret = arm_smmu_write_ctx_desc(master, IOMMU_NO_PASID, cd); - if (ret) - goto out_free_cd_tables; - mutex_unlock(&arm_smmu_asid_lock); return 0; -out_free_cd_tables: - arm_smmu_free_cd_tables(smmu_domain); -out_free_asid: - arm_smmu_free_asid(cd); out_unlock: mutex_unlock(&arm_smmu_asid_lock); return ret; @@ -2389,6 +2372,14 @@ static void arm_smmu_detach_dev(struct arm_smmu_master *master) master->domain = NULL; master->ats_enabled = false; arm_smmu_install_ste_for_dev(master); + /* + * Clearing the CD entry isn't strictly required to detach the domain + * since the table is uninstalled anyway, but it helps avoid confusion + * in the call to arm_smmu_write_ctx_desc on the next attach (which + * expects the entry to be empty). + */ + if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1 && master->cd_table.cdtab) + arm_smmu_write_ctx_desc(master, IOMMU_NO_PASID, NULL); } static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) @@ -2423,23 +2414,14 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) if (!smmu_domain->smmu) { smmu_domain->smmu = smmu; ret = arm_smmu_domain_finalise(domain, master); - if (ret) { + if (ret) smmu_domain->smmu = NULL; - goto out_unlock; - } - } else if (smmu_domain->smmu != smmu) { - ret = -EINVAL; - goto out_unlock; - } else if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1 && - master->ssid_bits != smmu_domain->cd_table.s1cdmax) { + } else if (smmu_domain->smmu != smmu) ret = -EINVAL; - goto out_unlock; - } else if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1 && - smmu_domain->cd_table.stall_enabled != - master->stall_enabled) { - ret = -EINVAL; - goto out_unlock; - } + + mutex_unlock(&smmu_domain->init_mutex); + if (ret) + return ret; master->domain = smmu_domain; @@ -2453,16 +2435,42 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) if (smmu_domain->stage != ARM_SMMU_DOMAIN_BYPASS) master->ats_enabled = arm_smmu_ats_supported(master); - arm_smmu_install_ste_for_dev(master); - spin_lock_irqsave(&smmu_domain->devices_lock, flags); list_add(&master->domain_head, &smmu_domain->devices); spin_unlock_irqrestore(&smmu_domain->devices_lock, flags); + if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) { + if (!master->cd_table.cdtab) { + ret = arm_smmu_alloc_cd_tables(master); + if (ret) { + master->domain = NULL; + goto out_list_del; + } + } + + /* + * Prevent SVA from concurrently modifying the CD or writing to + * the CD entry + */ + mutex_lock(&arm_smmu_asid_lock); + ret = arm_smmu_write_ctx_desc(master, IOMMU_NO_PASID, &smmu_domain->cd); + mutex_unlock(&arm_smmu_asid_lock); + if (ret) { + master->domain = NULL; + goto out_list_del; + } + } + + arm_smmu_install_ste_for_dev(master); + arm_smmu_enable_ats(master); + return 0; + +out_list_del: + spin_lock_irqsave(&smmu_domain->devices_lock, flags); + list_del(&master->domain_head); + spin_unlock_irqrestore(&smmu_domain->devices_lock, flags); -out_unlock: - mutex_unlock(&smmu_domain->init_mutex); return ret; } @@ -2707,6 +2715,8 @@ static void arm_smmu_release_device(struct device *dev) arm_smmu_detach_dev(master); arm_smmu_disable_pasid(master); arm_smmu_remove_master(master); + if (master->cd_table.cdtab) + arm_smmu_free_cd_tables(master); kfree(master); } diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h index d2fc0a9793e54..961205ba86d25 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h @@ -695,6 +695,8 @@ struct arm_smmu_master { struct arm_smmu_domain *domain; struct list_head domain_head; struct arm_smmu_stream *streams; + /* Locked by the iommu core using the group mutex */ + struct arm_smmu_ctx_desc_cfg cd_table; unsigned int num_streams; bool ats_enabled; bool stall_enabled; @@ -721,11 +723,8 @@ struct arm_smmu_domain { enum arm_smmu_domain_stage stage; union { - struct { struct arm_smmu_ctx_desc cd; - struct arm_smmu_ctx_desc_cfg cd_table; - }; - struct arm_smmu_s2_cfg s2_cfg; + struct arm_smmu_s2_cfg s2_cfg; }; struct iommu_domain domain; -- GitLab From 5e14313df2c8f81e22e62b4cd068ef3ee30914c8 Mon Sep 17 00:00:00 2001 From: Michael Shavit Date: Fri, 15 Sep 2023 21:17:38 +0800 Subject: [PATCH 0574/1451] iommu/arm-smmu-v3: Cleanup arm_smmu_domain_finalise Remove unused master parameter now that the CD table is allocated elsewhere. Reviewed-by: Nicolin Chen Reviewed-by: Jason Gunthorpe Signed-off-by: Michael Shavit Tested-by: Nicolin Chen Link: https://lore.kernel.org/r/20230915211705.v8.7.Iff18df41564b9df82bf40b3ec7af26b87f08ef6e@changeid Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index 96f68161695e9..49f3abb3e28ff 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -2077,7 +2077,6 @@ static void arm_smmu_domain_free(struct iommu_domain *domain) } static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, - struct arm_smmu_master *master, struct io_pgtable_cfg *pgtbl_cfg) { int ret; @@ -2115,7 +2114,6 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, } static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain, - struct arm_smmu_master *master, struct io_pgtable_cfg *pgtbl_cfg) { int vmid; @@ -2142,8 +2140,7 @@ static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain, return 0; } -static int arm_smmu_domain_finalise(struct iommu_domain *domain, - struct arm_smmu_master *master) +static int arm_smmu_domain_finalise(struct iommu_domain *domain) { int ret; unsigned long ias, oas; @@ -2151,7 +2148,6 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain, struct io_pgtable_cfg pgtbl_cfg; struct io_pgtable_ops *pgtbl_ops; int (*finalise_stage_fn)(struct arm_smmu_domain *, - struct arm_smmu_master *, struct io_pgtable_cfg *); struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); struct arm_smmu_device *smmu = smmu_domain->smmu; @@ -2203,7 +2199,7 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain, domain->geometry.aperture_end = (1UL << pgtbl_cfg.ias) - 1; domain->geometry.force_aperture = true; - ret = finalise_stage_fn(smmu_domain, master, &pgtbl_cfg); + ret = finalise_stage_fn(smmu_domain, &pgtbl_cfg); if (ret < 0) { free_io_pgtable_ops(pgtbl_ops); return ret; @@ -2413,7 +2409,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) if (!smmu_domain->smmu) { smmu_domain->smmu = smmu; - ret = arm_smmu_domain_finalise(domain, master); + ret = arm_smmu_domain_finalise(domain); if (ret) smmu_domain->smmu = NULL; } else if (smmu_domain->smmu != smmu) -- GitLab From 6032f58498b70f80103f467de4213f2ffbc2b062 Mon Sep 17 00:00:00 2001 From: Michael Shavit Date: Fri, 15 Sep 2023 21:17:39 +0800 Subject: [PATCH 0575/1451] iommu/arm-smmu-v3: Update comment about STE liveness Update the comment to reflect the fact that the STE is not always installed. arm_smmu_domain_finalise_s1 intentionnaly calls arm_smmu_write_ctx_desc while the STE is not installed. Reviewed-by: Nicolin Chen Reviewed-by: Jason Gunthorpe Signed-off-by: Michael Shavit Tested-by: Nicolin Chen Link: https://lore.kernel.org/r/20230915211705.v8.8.I7a8beb615e2520ad395d96df94b9ab9708ee0d9c@changeid Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index 49f3abb3e28ff..8fab0f3a09e5c 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -1091,7 +1091,7 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_master *master, int ssid, cdptr[3] = cpu_to_le64(cd->mair); /* - * STE is live, and the SMMU might read dwords of this CD in any + * STE may be live, and the SMMU might read dwords of this CD in any * order. Ensure that it observes valid values before reading * V=1. */ -- GitLab From 475918e9c4ebda495f507d4b9612999d31512748 Mon Sep 17 00:00:00 2001 From: Michael Shavit Date: Fri, 15 Sep 2023 21:17:40 +0800 Subject: [PATCH 0576/1451] iommu/arm-smmu-v3: Rename cdcfg to cd_table cdcfg is a confusing name, especially given other variables with the cfg suffix in this driver. cd_table more clearly describes what is being operated on. Tested-by: Nicolin Chen Reviewed-by: Jason Gunthorpe Reviewed-by: Nicolin Chen Signed-off-by: Michael Shavit Link: https://lore.kernel.org/r/20230915211705.v8.9.I5ee79793b444ddb933e8bc1eb7b77e728d7f8350@changeid Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 70 ++++++++++----------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index 8fab0f3a09e5c..7445454c2af24 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -1025,18 +1025,18 @@ static __le64 *arm_smmu_get_cd_ptr(struct arm_smmu_master *master, u32 ssid) unsigned int idx; struct arm_smmu_l1_ctx_desc *l1_desc; struct arm_smmu_device *smmu = master->smmu; - struct arm_smmu_ctx_desc_cfg *cdcfg = &master->cd_table; + struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table; - if (cdcfg->s1fmt == STRTAB_STE_0_S1FMT_LINEAR) - return cdcfg->cdtab + ssid * CTXDESC_CD_DWORDS; + if (cd_table->s1fmt == STRTAB_STE_0_S1FMT_LINEAR) + return cd_table->cdtab + ssid * CTXDESC_CD_DWORDS; idx = ssid >> CTXDESC_SPLIT; - l1_desc = &cdcfg->l1_desc[idx]; + l1_desc = &cd_table->l1_desc[idx]; if (!l1_desc->l2ptr) { if (arm_smmu_alloc_cd_leaf_table(smmu, l1_desc)) return NULL; - l1ptr = cdcfg->cdtab + idx * CTXDESC_L1_DESC_DWORDS; + l1ptr = cd_table->cdtab + idx * CTXDESC_L1_DESC_DWORDS; arm_smmu_write_cd_l1_desc(l1ptr, l1_desc); /* An invalid L1CD can be cached */ arm_smmu_sync_cd(master, ssid, false); @@ -1131,35 +1131,35 @@ static int arm_smmu_alloc_cd_tables(struct arm_smmu_master *master) size_t l1size; size_t max_contexts; struct arm_smmu_device *smmu = master->smmu; - struct arm_smmu_ctx_desc_cfg *cdcfg = &master->cd_table; + struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table; - cdcfg->stall_enabled = master->stall_enabled; - cdcfg->s1cdmax = master->ssid_bits; - max_contexts = 1 << cdcfg->s1cdmax; + cd_table->stall_enabled = master->stall_enabled; + cd_table->s1cdmax = master->ssid_bits; + max_contexts = 1 << cd_table->s1cdmax; if (!(smmu->features & ARM_SMMU_FEAT_2_LVL_CDTAB) || max_contexts <= CTXDESC_L2_ENTRIES) { - cdcfg->s1fmt = STRTAB_STE_0_S1FMT_LINEAR; - cdcfg->num_l1_ents = max_contexts; + cd_table->s1fmt = STRTAB_STE_0_S1FMT_LINEAR; + cd_table->num_l1_ents = max_contexts; l1size = max_contexts * (CTXDESC_CD_DWORDS << 3); } else { - cdcfg->s1fmt = STRTAB_STE_0_S1FMT_64K_L2; - cdcfg->num_l1_ents = DIV_ROUND_UP(max_contexts, + cd_table->s1fmt = STRTAB_STE_0_S1FMT_64K_L2; + cd_table->num_l1_ents = DIV_ROUND_UP(max_contexts, CTXDESC_L2_ENTRIES); - cdcfg->l1_desc = devm_kcalloc(smmu->dev, cdcfg->num_l1_ents, - sizeof(*cdcfg->l1_desc), + cd_table->l1_desc = devm_kcalloc(smmu->dev, cd_table->num_l1_ents, + sizeof(*cd_table->l1_desc), GFP_KERNEL); - if (!cdcfg->l1_desc) + if (!cd_table->l1_desc) return -ENOMEM; - l1size = cdcfg->num_l1_ents * (CTXDESC_L1_DESC_DWORDS << 3); + l1size = cd_table->num_l1_ents * (CTXDESC_L1_DESC_DWORDS << 3); } - cdcfg->cdtab = dmam_alloc_coherent(smmu->dev, l1size, &cdcfg->cdtab_dma, + cd_table->cdtab = dmam_alloc_coherent(smmu->dev, l1size, &cd_table->cdtab_dma, GFP_KERNEL); - if (!cdcfg->cdtab) { + if (!cd_table->cdtab) { dev_warn(smmu->dev, "failed to allocate context descriptor\n"); ret = -ENOMEM; goto err_free_l1; @@ -1168,9 +1168,9 @@ static int arm_smmu_alloc_cd_tables(struct arm_smmu_master *master) return 0; err_free_l1: - if (cdcfg->l1_desc) { - devm_kfree(smmu->dev, cdcfg->l1_desc); - cdcfg->l1_desc = NULL; + if (cd_table->l1_desc) { + devm_kfree(smmu->dev, cd_table->l1_desc); + cd_table->l1_desc = NULL; } return ret; } @@ -1180,30 +1180,30 @@ static void arm_smmu_free_cd_tables(struct arm_smmu_master *master) int i; size_t size, l1size; struct arm_smmu_device *smmu = master->smmu; - struct arm_smmu_ctx_desc_cfg *cdcfg = &master->cd_table; + struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table; - if (cdcfg->l1_desc) { + if (cd_table->l1_desc) { size = CTXDESC_L2_ENTRIES * (CTXDESC_CD_DWORDS << 3); - for (i = 0; i < cdcfg->num_l1_ents; i++) { - if (!cdcfg->l1_desc[i].l2ptr) + for (i = 0; i < cd_table->num_l1_ents; i++) { + if (!cd_table->l1_desc[i].l2ptr) continue; dmam_free_coherent(smmu->dev, size, - cdcfg->l1_desc[i].l2ptr, - cdcfg->l1_desc[i].l2ptr_dma); + cd_table->l1_desc[i].l2ptr, + cd_table->l1_desc[i].l2ptr_dma); } - devm_kfree(smmu->dev, cdcfg->l1_desc); - cdcfg->l1_desc = NULL; + devm_kfree(smmu->dev, cd_table->l1_desc); + cd_table->l1_desc = NULL; - l1size = cdcfg->num_l1_ents * (CTXDESC_L1_DESC_DWORDS << 3); + l1size = cd_table->num_l1_ents * (CTXDESC_L1_DESC_DWORDS << 3); } else { - l1size = cdcfg->num_l1_ents * (CTXDESC_CD_DWORDS << 3); + l1size = cd_table->num_l1_ents * (CTXDESC_CD_DWORDS << 3); } - dmam_free_coherent(smmu->dev, l1size, cdcfg->cdtab, cdcfg->cdtab_dma); - cdcfg->cdtab_dma = 0; - cdcfg->cdtab = NULL; + dmam_free_coherent(smmu->dev, l1size, cd_table->cdtab, cd_table->cdtab_dma); + cd_table->cdtab_dma = 0; + cd_table->cdtab = NULL; } bool arm_smmu_free_asid(struct arm_smmu_ctx_desc *cd) -- GitLab From d912aed14fe412038379b1a90d1ae5a02307e830 Mon Sep 17 00:00:00 2001 From: Michael Shavit Date: Tue, 5 Sep 2023 19:49:12 +0800 Subject: [PATCH 0577/1451] iommu/arm-smmu-v3-sva: Remove unused iommu_sva handle The __arm_smmu_sva_bind function returned an unused iommu_sva handle that can be removed. Signed-off-by: Michael Shavit Reviewed-by: Jason Gunthorpe Link: https://lore.kernel.org/r/20230905194849.v1.1.Ib483f67c9e2ad90ea2254b4b5ac696e4b68aa638@changeid Signed-off-by: Will Deacon --- .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c index df66fe43a9853..ce895c5ce42e8 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c @@ -25,7 +25,6 @@ struct arm_smmu_mmu_notifier { #define mn_to_smmu(mn) container_of(mn, struct arm_smmu_mmu_notifier, mn) struct arm_smmu_bond { - struct iommu_sva sva; struct mm_struct *mm; struct arm_smmu_mmu_notifier *smmu_mn; struct list_head list; @@ -376,8 +375,7 @@ static void arm_smmu_mmu_notifier_put(struct arm_smmu_mmu_notifier *smmu_mn) arm_smmu_free_shared_cd(cd); } -static struct iommu_sva * -__arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm) +static int __arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm) { int ret; struct arm_smmu_bond *bond; @@ -386,7 +384,7 @@ __arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm) struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); if (!master || !master->sva_enabled) - return ERR_PTR(-ENODEV); + return -ENODEV; /* If bind() was already called for this {dev, mm} pair, reuse it. */ list_for_each_entry(bond, &master->bonds, list) { @@ -398,10 +396,9 @@ __arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm) bond = kzalloc(sizeof(*bond), GFP_KERNEL); if (!bond) - return ERR_PTR(-ENOMEM); + return -ENOMEM; bond->mm = mm; - bond->sva.dev = dev; refcount_set(&bond->refs, 1); bond->smmu_mn = arm_smmu_mmu_notifier_get(smmu_domain, mm); @@ -411,11 +408,11 @@ __arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm) } list_add(&bond->list, &master->bonds); - return &bond->sva; + return 0; err_free_bond: kfree(bond); - return ERR_PTR(ret); + return ret; } bool arm_smmu_sva_supported(struct arm_smmu_device *smmu) @@ -593,13 +590,10 @@ static int arm_smmu_sva_set_dev_pasid(struct iommu_domain *domain, struct device *dev, ioasid_t id) { int ret = 0; - struct iommu_sva *handle; struct mm_struct *mm = domain->mm; mutex_lock(&sva_lock); - handle = __arm_smmu_sva_bind(dev, mm); - if (IS_ERR(handle)) - ret = PTR_ERR(handle); + ret = __arm_smmu_sva_bind(dev, mm); mutex_unlock(&sva_lock); return ret; -- GitLab From 37ed36448fcd73be197c87ce291d96eeb4d55c00 Mon Sep 17 00:00:00 2001 From: Michael Shavit Date: Tue, 5 Sep 2023 19:49:13 +0800 Subject: [PATCH 0578/1451] iommu/arm-smmu-v3-sva: Remove bond refcount Always allocate a new arm_smmu_bond in __arm_smmu_sva_bind and remove the bond refcount since arm_smmu_bond can never be shared across calls to __arm_smmu_sva_bind. The iommu framework will not allocate multiple SVA domains for the same (device/mm) pair, nor will it call set_dev_pasid for a device if a domain is already attached on the given pasid. There's also a one-to-one mapping between MM and PASID. __arm_smmu_sva_bind is therefore never called with the same (device/mm) pair, and so there's no reason to try and normalize allocations of the arm_smmu_bond struct for a (device/mm) pair across set_dev_pasid. Signed-off-by: Michael Shavit Reviewed-by: Jason Gunthorpe Link: https://lore.kernel.org/r/20230905194849.v1.2.Id3ab7cf665bcead097654937233a645722a4cce3@changeid Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c index ce895c5ce42e8..353248ab18e76 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c @@ -28,7 +28,6 @@ struct arm_smmu_bond { struct mm_struct *mm; struct arm_smmu_mmu_notifier *smmu_mn; struct list_head list; - refcount_t refs; }; #define sva_to_bond(handle) \ @@ -386,20 +385,11 @@ static int __arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm) if (!master || !master->sva_enabled) return -ENODEV; - /* If bind() was already called for this {dev, mm} pair, reuse it. */ - list_for_each_entry(bond, &master->bonds, list) { - if (bond->mm == mm) { - refcount_inc(&bond->refs); - return &bond->sva; - } - } - bond = kzalloc(sizeof(*bond), GFP_KERNEL); if (!bond) return -ENOMEM; bond->mm = mm; - refcount_set(&bond->refs, 1); bond->smmu_mn = arm_smmu_mmu_notifier_get(smmu_domain, mm); if (IS_ERR(bond->smmu_mn)) { @@ -578,7 +568,7 @@ void arm_smmu_sva_remove_dev_pasid(struct iommu_domain *domain, } } - if (!WARN_ON(!bond) && refcount_dec_and_test(&bond->refs)) { + if (!WARN_ON(!bond)) { list_del(&bond->list); arm_smmu_mmu_notifier_put(bond->smmu_mn); kfree(bond); -- GitLab From 7a3663c2e41f38daf876b23504f1396317f98fee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 8 Aug 2023 08:26:08 +0200 Subject: [PATCH 0579/1451] pwm: jz4740: Consistently name driver data "jz" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most but not all pointers to driver data are already called "jz": $ git grep 'struct jz4740_pwm_chip \*' v6.5-rc1 -- drivers/pwm/pwm-jz4740.c v6.5-rc1:drivers/pwm/pwm-jz4740.c:static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip) v6.5-rc1:drivers/pwm/pwm-jz4740.c:static bool jz4740_pwm_can_use_chn(struct jz4740_pwm_chip *jz, v6.5-rc1:drivers/pwm/pwm-jz4740.c: struct jz4740_pwm_chip *jz = to_jz4740(chip); v6.5-rc1:drivers/pwm/pwm-jz4740.c: struct jz4740_pwm_chip *jz = to_jz4740(chip); v6.5-rc1:drivers/pwm/pwm-jz4740.c: struct jz4740_pwm_chip *jz = to_jz4740(chip); v6.5-rc1:drivers/pwm/pwm-jz4740.c: struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip); v6.5-rc1:drivers/pwm/pwm-jz4740.c: struct jz4740_pwm_chip *jz4740; Adapt the two variables called "jz4740" to use the same name for consistency. Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/r/20230808062608.897710-1-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-jz4740.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c index ef1293f2a897e..6b21242662732 100644 --- a/drivers/pwm/pwm-jz4740.c +++ b/drivers/pwm/pwm-jz4740.c @@ -121,7 +121,7 @@ static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state) { - struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip); + struct jz4740_pwm_chip *jz = to_jz4740(pwm->chip); unsigned long long tmp = 0xffffull * NSEC_PER_SEC; struct clk *clk = pwm_get_chip_data(pwm); unsigned long period, duty; @@ -173,16 +173,16 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, } /* Reset counter to 0 */ - regmap_write(jz4740->map, TCU_REG_TCNTc(pwm->hwpwm), 0); + regmap_write(jz->map, TCU_REG_TCNTc(pwm->hwpwm), 0); /* Set duty */ - regmap_write(jz4740->map, TCU_REG_TDHRc(pwm->hwpwm), duty); + regmap_write(jz->map, TCU_REG_TDHRc(pwm->hwpwm), duty); /* Set period */ - regmap_write(jz4740->map, TCU_REG_TDFRc(pwm->hwpwm), period); + regmap_write(jz->map, TCU_REG_TDFRc(pwm->hwpwm), period); /* Set abrupt shutdown */ - regmap_set_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm), + regmap_set_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm), TCU_TCSR_PWM_SD); /* @@ -199,10 +199,10 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, * state instead of its inactive state. */ if ((state->polarity == PWM_POLARITY_NORMAL) ^ state->enabled) - regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm), + regmap_update_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm), TCU_TCSR_PWM_INITL_HIGH, 0); else - regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm), + regmap_update_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm), TCU_TCSR_PWM_INITL_HIGH, TCU_TCSR_PWM_INITL_HIGH); @@ -222,28 +222,28 @@ static const struct pwm_ops jz4740_pwm_ops = { static int jz4740_pwm_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct jz4740_pwm_chip *jz4740; + struct jz4740_pwm_chip *jz; const struct soc_info *info; info = device_get_match_data(dev); if (!info) return -EINVAL; - jz4740 = devm_kzalloc(dev, sizeof(*jz4740), GFP_KERNEL); - if (!jz4740) + jz = devm_kzalloc(dev, sizeof(*jz), GFP_KERNEL); + if (!jz) return -ENOMEM; - jz4740->map = device_node_to_regmap(dev->parent->of_node); - if (IS_ERR(jz4740->map)) { - dev_err(dev, "regmap not found: %ld\n", PTR_ERR(jz4740->map)); - return PTR_ERR(jz4740->map); + jz->map = device_node_to_regmap(dev->parent->of_node); + if (IS_ERR(jz->map)) { + dev_err(dev, "regmap not found: %ld\n", PTR_ERR(jz->map)); + return PTR_ERR(jz->map); } - jz4740->chip.dev = dev; - jz4740->chip.ops = &jz4740_pwm_ops; - jz4740->chip.npwm = info->num_pwms; + jz->chip.dev = dev; + jz->chip.ops = &jz4740_pwm_ops; + jz->chip.npwm = info->num_pwms; - return devm_pwmchip_add(dev, &jz4740->chip); + return devm_pwmchip_add(dev, &jz->chip); } static const struct soc_info jz4740_soc_info = { -- GitLab From 384461abcab6602abc06c2dfb8fb99beeeaa12b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 4 Aug 2023 16:27:06 +0200 Subject: [PATCH 0580/1451] pwm: Manage owner assignment implicitly for drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of requiring each driver to care for assigning the owner member of struct pwm_ops, handle that implicitly using a macro. Note that the owner member has to be moved to struct pwm_chip, as the ops structure usually lives in read-only memory and so cannot be modified. The upside is that new low level drivers cannot forget the assignment and save one line each. The pwm-crc driver didn't assign .owner, that's not a problem in practice though as the driver cannot be compiled as a module. Acked-by: Andy Shevchenko # Intel LPSS Reviewed-by: Florian Fainelli # pwm-{bcm,brcm}*.c Acked-by: Jernej Skrabec # sun4i Acked-by: Andi Shyti Acked-by: Nobuhiro Iwamatsu # pwm-visconti Acked-by: Heiko Stuebner # pwm-rockchip Acked-by: Michael Walle # pwm-sl28cpld Acked-by: Neil Armstrong # pwm-meson Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20230804142707.412137-2-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/gpio/gpio-mvebu.c | 1 - drivers/gpu/drm/bridge/ti-sn65dsi86.c | 1 - drivers/leds/rgb/leds-qcom-lpg.c | 1 - drivers/pwm/core.c | 24 ++++++++++++++---------- drivers/pwm/pwm-ab8500.c | 1 - drivers/pwm/pwm-apple.c | 1 - drivers/pwm/pwm-atmel-hlcdc.c | 1 - drivers/pwm/pwm-atmel-tcb.c | 1 - drivers/pwm/pwm-atmel.c | 1 - drivers/pwm/pwm-bcm-iproc.c | 1 - drivers/pwm/pwm-bcm-kona.c | 1 - drivers/pwm/pwm-bcm2835.c | 1 - drivers/pwm/pwm-berlin.c | 1 - drivers/pwm/pwm-brcmstb.c | 1 - drivers/pwm/pwm-clk.c | 1 - drivers/pwm/pwm-clps711x.c | 1 - drivers/pwm/pwm-cros-ec.c | 1 - drivers/pwm/pwm-dwc.c | 1 - drivers/pwm/pwm-ep93xx.c | 1 - drivers/pwm/pwm-fsl-ftm.c | 1 - drivers/pwm/pwm-hibvt.c | 1 - drivers/pwm/pwm-img.c | 1 - drivers/pwm/pwm-imx-tpm.c | 1 - drivers/pwm/pwm-imx1.c | 1 - drivers/pwm/pwm-imx27.c | 1 - drivers/pwm/pwm-intel-lgm.c | 1 - drivers/pwm/pwm-iqs620a.c | 1 - drivers/pwm/pwm-jz4740.c | 1 - drivers/pwm/pwm-keembay.c | 1 - drivers/pwm/pwm-lp3943.c | 1 - drivers/pwm/pwm-lpc18xx-sct.c | 1 - drivers/pwm/pwm-lpc32xx.c | 1 - drivers/pwm/pwm-lpss.c | 1 - drivers/pwm/pwm-mediatek.c | 1 - drivers/pwm/pwm-meson.c | 1 - drivers/pwm/pwm-microchip-core.c | 1 - drivers/pwm/pwm-mtk-disp.c | 1 - drivers/pwm/pwm-mxs.c | 1 - drivers/pwm/pwm-ntxec.c | 1 - drivers/pwm/pwm-omap-dmtimer.c | 1 - drivers/pwm/pwm-pca9685.c | 1 - drivers/pwm/pwm-pxa.c | 1 - drivers/pwm/pwm-raspberrypi-poe.c | 1 - drivers/pwm/pwm-rcar.c | 1 - drivers/pwm/pwm-renesas-tpu.c | 1 - drivers/pwm/pwm-rockchip.c | 1 - drivers/pwm/pwm-rz-mtu3.c | 1 - drivers/pwm/pwm-samsung.c | 1 - drivers/pwm/pwm-sifive.c | 1 - drivers/pwm/pwm-sl28cpld.c | 1 - drivers/pwm/pwm-spear.c | 1 - drivers/pwm/pwm-sprd.c | 1 - drivers/pwm/pwm-sti.c | 1 - drivers/pwm/pwm-stm32-lp.c | 1 - drivers/pwm/pwm-stm32.c | 1 - drivers/pwm/pwm-stmpe.c | 1 - drivers/pwm/pwm-sun4i.c | 1 - drivers/pwm/pwm-sunplus.c | 1 - drivers/pwm/pwm-tegra.c | 1 - drivers/pwm/pwm-tiecap.c | 1 - drivers/pwm/pwm-tiehrpwm.c | 1 - drivers/pwm/pwm-twl-led.c | 2 -- drivers/pwm/pwm-twl.c | 2 -- drivers/pwm/pwm-visconti.c | 1 - drivers/pwm/pwm-vt8500.c | 1 - drivers/pwm/pwm-xilinx.c | 1 - drivers/staging/greybus/pwm.c | 1 - include/linux/pwm.h | 10 ++++++---- 68 files changed, 20 insertions(+), 82 deletions(-) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 67497116ce27d..64acd497a341a 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -756,7 +756,6 @@ static const struct pwm_ops mvebu_pwm_ops = { .free = mvebu_pwm_free, .get_state = mvebu_pwm_get_state, .apply = mvebu_pwm_apply, - .owner = THIS_MODULE, }; static void __maybe_unused mvebu_pwm_suspend(struct mvebu_gpio_chip *mvchip) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index f448b903e1907..08e8c4f333e38 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -1580,7 +1580,6 @@ static const struct pwm_ops ti_sn_pwm_ops = { .free = ti_sn_pwm_free, .apply = ti_sn_pwm_apply, .get_state = ti_sn_pwm_get_state, - .owner = THIS_MODULE, }; static int ti_sn_pwm_probe(struct auxiliary_device *adev, diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c index df469aaa7e6e7..c8525f59748c2 100644 --- a/drivers/leds/rgb/leds-qcom-lpg.c +++ b/drivers/leds/rgb/leds-qcom-lpg.c @@ -1085,7 +1085,6 @@ static const struct pwm_ops lpg_pwm_ops = { .request = lpg_pwm_request, .apply = lpg_pwm_apply, .get_state = lpg_pwm_get_state, - .owner = THIS_MODULE, }; static int lpg_add_pwm(struct lpg *lpg) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index dc66e3405bf50..a2824eb4e236d 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -89,13 +89,13 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label) if (test_bit(PWMF_REQUESTED, &pwm->flags)) return -EBUSY; - if (!try_module_get(pwm->chip->ops->owner)) + if (!try_module_get(pwm->chip->owner)) return -ENODEV; if (pwm->chip->ops->request) { err = pwm->chip->ops->request(pwm->chip, pwm); if (err) { - module_put(pwm->chip->ops->owner); + module_put(pwm->chip->owner); return err; } } @@ -253,14 +253,16 @@ static bool pwm_ops_check(const struct pwm_chip *chip) } /** - * pwmchip_add() - register a new PWM chip + * __pwmchip_add() - register a new PWM chip * @chip: the PWM chip to add + * @owner: reference to the module providing the chip. * - * Register a new PWM chip. + * Register a new PWM chip. @owner is supposed to be THIS_MODULE, use the + * pwmchip_add wrapper to do this right. * * Returns: 0 on success or a negative error code on failure. */ -int pwmchip_add(struct pwm_chip *chip) +int __pwmchip_add(struct pwm_chip *chip, struct module *owner) { struct pwm_device *pwm; unsigned int i; @@ -272,6 +274,8 @@ int pwmchip_add(struct pwm_chip *chip) if (!pwm_ops_check(chip)) return -EINVAL; + chip->owner = owner; + chip->pwms = kcalloc(chip->npwm, sizeof(*pwm), GFP_KERNEL); if (!chip->pwms) return -ENOMEM; @@ -306,7 +310,7 @@ int pwmchip_add(struct pwm_chip *chip) return 0; } -EXPORT_SYMBOL_GPL(pwmchip_add); +EXPORT_SYMBOL_GPL(__pwmchip_add); /** * pwmchip_remove() - remove a PWM chip @@ -338,17 +342,17 @@ static void devm_pwmchip_remove(void *data) pwmchip_remove(chip); } -int devm_pwmchip_add(struct device *dev, struct pwm_chip *chip) +int __devm_pwmchip_add(struct device *dev, struct pwm_chip *chip, struct module *owner) { int ret; - ret = pwmchip_add(chip); + ret = __pwmchip_add(chip, owner); if (ret) return ret; return devm_add_action_or_reset(dev, devm_pwmchip_remove, chip); } -EXPORT_SYMBOL_GPL(devm_pwmchip_add); +EXPORT_SYMBOL_GPL(__devm_pwmchip_add); /** * pwm_request_from_chip() - request a PWM device relative to a PWM chip @@ -979,7 +983,7 @@ void pwm_put(struct pwm_device *pwm) pwm_set_chip_data(pwm, NULL); pwm->label = NULL; - module_put(pwm->chip->ops->owner); + module_put(pwm->chip->owner); out: mutex_unlock(&pwm_lock); } diff --git a/drivers/pwm/pwm-ab8500.c b/drivers/pwm/pwm-ab8500.c index 583a7d69c7415..670d33daea846 100644 --- a/drivers/pwm/pwm-ab8500.c +++ b/drivers/pwm/pwm-ab8500.c @@ -181,7 +181,6 @@ static int ab8500_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops ab8500_pwm_ops = { .apply = ab8500_pwm_apply, .get_state = ab8500_pwm_get_state, - .owner = THIS_MODULE, }; static int ab8500_pwm_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-apple.c b/drivers/pwm/pwm-apple.c index 8e7d67fb5fbef..4d755b628d9e7 100644 --- a/drivers/pwm/pwm-apple.c +++ b/drivers/pwm/pwm-apple.c @@ -99,7 +99,6 @@ static int apple_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops apple_pwm_ops = { .apply = apple_pwm_apply, .get_state = apple_pwm_get_state, - .owner = THIS_MODULE, }; static int apple_pwm_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c index e271d920151e4..07920e0347575 100644 --- a/drivers/pwm/pwm-atmel-hlcdc.c +++ b/drivers/pwm/pwm-atmel-hlcdc.c @@ -170,7 +170,6 @@ static int atmel_hlcdc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops atmel_hlcdc_pwm_ops = { .apply = atmel_hlcdc_pwm_apply, - .owner = THIS_MODULE, }; static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_at91sam9x5_errata = { diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c index c00dd37c5fbd8..98b33c016c3c7 100644 --- a/drivers/pwm/pwm-atmel-tcb.c +++ b/drivers/pwm/pwm-atmel-tcb.c @@ -364,7 +364,6 @@ static const struct pwm_ops atmel_tcb_pwm_ops = { .request = atmel_tcb_pwm_request, .free = atmel_tcb_pwm_free, .apply = atmel_tcb_pwm_apply, - .owner = THIS_MODULE, }; static struct atmel_tcb_config tcb_rm9200_config = { diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 35ae876bf2ea2..47bcc8a3bf9d5 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -402,7 +402,6 @@ static int atmel_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops atmel_pwm_ops = { .apply = atmel_pwm_apply, .get_state = atmel_pwm_get_state, - .owner = THIS_MODULE, }; static const struct atmel_pwm_data atmel_sam9rl_pwm_data = { diff --git a/drivers/pwm/pwm-bcm-iproc.c b/drivers/pwm/pwm-bcm-iproc.c index 7d70b6f186a6f..1da902440df24 100644 --- a/drivers/pwm/pwm-bcm-iproc.c +++ b/drivers/pwm/pwm-bcm-iproc.c @@ -183,7 +183,6 @@ static int iproc_pwmc_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops iproc_pwm_ops = { .apply = iproc_pwmc_apply, .get_state = iproc_pwmc_get_state, - .owner = THIS_MODULE, }; static int iproc_pwmc_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c index e5b00cc9f7a76..15d6ed03c3ce0 100644 --- a/drivers/pwm/pwm-bcm-kona.c +++ b/drivers/pwm/pwm-bcm-kona.c @@ -269,7 +269,6 @@ static int kona_pwmc_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops kona_pwm_ops = { .apply = kona_pwmc_apply, - .owner = THIS_MODULE, }; static int kona_pwmc_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c index bdfc2a5ec0d69..af318a35d510e 100644 --- a/drivers/pwm/pwm-bcm2835.c +++ b/drivers/pwm/pwm-bcm2835.c @@ -129,7 +129,6 @@ static const struct pwm_ops bcm2835_pwm_ops = { .request = bcm2835_pwm_request, .free = bcm2835_pwm_free, .apply = bcm2835_pwm_apply, - .owner = THIS_MODULE, }; static int bcm2835_pwm_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c index 0971c666afd13..6a6641fc4fa1b 100644 --- a/drivers/pwm/pwm-berlin.c +++ b/drivers/pwm/pwm-berlin.c @@ -205,7 +205,6 @@ static const struct pwm_ops berlin_pwm_ops = { .request = berlin_pwm_request, .free = berlin_pwm_free, .apply = berlin_pwm_apply, - .owner = THIS_MODULE, }; static const struct of_device_id berlin_pwm_match[] = { diff --git a/drivers/pwm/pwm-brcmstb.c b/drivers/pwm/pwm-brcmstb.c index a3faa9a3de7cc..96967f8a8dad9 100644 --- a/drivers/pwm/pwm-brcmstb.c +++ b/drivers/pwm/pwm-brcmstb.c @@ -220,7 +220,6 @@ static int brcmstb_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops brcmstb_pwm_ops = { .apply = brcmstb_pwm_apply, - .owner = THIS_MODULE, }; static const struct of_device_id brcmstb_pwm_of_match[] = { diff --git a/drivers/pwm/pwm-clk.c b/drivers/pwm/pwm-clk.c index 0ee4d2aee4df0..9dd88b386907c 100644 --- a/drivers/pwm/pwm-clk.c +++ b/drivers/pwm/pwm-clk.c @@ -77,7 +77,6 @@ static int pwm_clk_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops pwm_clk_ops = { .apply = pwm_clk_apply, - .owner = THIS_MODULE, }; static int pwm_clk_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-clps711x.c b/drivers/pwm/pwm-clps711x.c index b0d91142da8d0..42179b3f7ec39 100644 --- a/drivers/pwm/pwm-clps711x.c +++ b/drivers/pwm/pwm-clps711x.c @@ -72,7 +72,6 @@ static int clps711x_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops clps711x_pwm_ops = { .request = clps711x_pwm_request, .apply = clps711x_pwm_apply, - .owner = THIS_MODULE, }; static struct pwm_device *clps711x_pwm_xlate(struct pwm_chip *chip, diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c index baaac0c33aa06..500504c7d459b 100644 --- a/drivers/pwm/pwm-cros-ec.c +++ b/drivers/pwm/pwm-cros-ec.c @@ -241,7 +241,6 @@ static const struct pwm_ops cros_ec_pwm_ops = { .free = cros_ec_pwm_free, .get_state = cros_ec_pwm_get_state, .apply = cros_ec_pwm_apply, - .owner = THIS_MODULE, }; /* diff --git a/drivers/pwm/pwm-dwc.c b/drivers/pwm/pwm-dwc.c index 3bbb26c862c35..53fe00ccd47ef 100644 --- a/drivers/pwm/pwm-dwc.c +++ b/drivers/pwm/pwm-dwc.c @@ -195,7 +195,6 @@ static int dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops dwc_pwm_ops = { .apply = dwc_pwm_apply, .get_state = dwc_pwm_get_state, - .owner = THIS_MODULE, }; static struct dwc_pwm *dwc_pwm_alloc(struct device *dev) diff --git a/drivers/pwm/pwm-ep93xx.c b/drivers/pwm/pwm-ep93xx.c index c45a75e65c869..51e072572a87b 100644 --- a/drivers/pwm/pwm-ep93xx.c +++ b/drivers/pwm/pwm-ep93xx.c @@ -159,7 +159,6 @@ static const struct pwm_ops ep93xx_pwm_ops = { .request = ep93xx_pwm_request, .free = ep93xx_pwm_free, .apply = ep93xx_pwm_apply, - .owner = THIS_MODULE, }; static int ep93xx_pwm_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c index b7c6045c5d089..d1b6d1aa47736 100644 --- a/drivers/pwm/pwm-fsl-ftm.c +++ b/drivers/pwm/pwm-fsl-ftm.c @@ -350,7 +350,6 @@ static const struct pwm_ops fsl_pwm_ops = { .request = fsl_pwm_request, .free = fsl_pwm_free, .apply = fsl_pwm_apply, - .owner = THIS_MODULE, }; static int fsl_pwm_init(struct fsl_pwm_chip *fpc) diff --git a/drivers/pwm/pwm-hibvt.c b/drivers/pwm/pwm-hibvt.c index f7ba6fe9a349a..c435776e2f786 100644 --- a/drivers/pwm/pwm-hibvt.c +++ b/drivers/pwm/pwm-hibvt.c @@ -185,7 +185,6 @@ static const struct pwm_ops hibvt_pwm_ops = { .get_state = hibvt_pwm_get_state, .apply = hibvt_pwm_apply, - .owner = THIS_MODULE, }; static int hibvt_pwm_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-img.c b/drivers/pwm/pwm-img.c index 326af85888e7b..116fa060e3029 100644 --- a/drivers/pwm/pwm-img.c +++ b/drivers/pwm/pwm-img.c @@ -208,7 +208,6 @@ static int img_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops img_pwm_ops = { .apply = img_pwm_apply, - .owner = THIS_MODULE, }; static const struct img_pwm_soc_data pistachio_pwm = { diff --git a/drivers/pwm/pwm-imx-tpm.c b/drivers/pwm/pwm-imx-tpm.c index 98ab65c896850..fe8bf598d3889 100644 --- a/drivers/pwm/pwm-imx-tpm.c +++ b/drivers/pwm/pwm-imx-tpm.c @@ -332,7 +332,6 @@ static const struct pwm_ops imx_tpm_pwm_ops = { .free = pwm_imx_tpm_free, .get_state = pwm_imx_tpm_get_state, .apply = pwm_imx_tpm_apply, - .owner = THIS_MODULE, }; static int pwm_imx_tpm_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-imx1.c b/drivers/pwm/pwm-imx1.c index 0651983bed190..d175d895f22a3 100644 --- a/drivers/pwm/pwm-imx1.c +++ b/drivers/pwm/pwm-imx1.c @@ -146,7 +146,6 @@ static int pwm_imx1_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops pwm_imx1_ops = { .apply = pwm_imx1_apply, - .owner = THIS_MODULE, }; static const struct of_device_id pwm_imx1_dt_ids[] = { diff --git a/drivers/pwm/pwm-imx27.c b/drivers/pwm/pwm-imx27.c index 29a3089c534cd..7d9bc43f12b0e 100644 --- a/drivers/pwm/pwm-imx27.c +++ b/drivers/pwm/pwm-imx27.c @@ -296,7 +296,6 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops pwm_imx27_ops = { .apply = pwm_imx27_apply, .get_state = pwm_imx27_get_state, - .owner = THIS_MODULE, }; static const struct of_device_id pwm_imx27_dt_ids[] = { diff --git a/drivers/pwm/pwm-intel-lgm.c b/drivers/pwm/pwm-intel-lgm.c index 0cd7dd548e82f..54ecae7f937ed 100644 --- a/drivers/pwm/pwm-intel-lgm.c +++ b/drivers/pwm/pwm-intel-lgm.c @@ -107,7 +107,6 @@ static int lgm_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops lgm_pwm_ops = { .get_state = lgm_pwm_get_state, .apply = lgm_pwm_apply, - .owner = THIS_MODULE, }; static void lgm_pwm_init(struct lgm_pwm_chip *pc) diff --git a/drivers/pwm/pwm-iqs620a.c b/drivers/pwm/pwm-iqs620a.c index 47b3141135f38..378ab036edfec 100644 --- a/drivers/pwm/pwm-iqs620a.c +++ b/drivers/pwm/pwm-iqs620a.c @@ -166,7 +166,6 @@ static int iqs620_pwm_notifier(struct notifier_block *notifier, static const struct pwm_ops iqs620_pwm_ops = { .apply = iqs620_pwm_apply, .get_state = iqs620_pwm_get_state, - .owner = THIS_MODULE, }; static void iqs620_pwm_notifier_unregister(void *context) diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c index 6b21242662732..49a6e28d1d986 100644 --- a/drivers/pwm/pwm-jz4740.c +++ b/drivers/pwm/pwm-jz4740.c @@ -216,7 +216,6 @@ static const struct pwm_ops jz4740_pwm_ops = { .request = jz4740_pwm_request, .free = jz4740_pwm_free, .apply = jz4740_pwm_apply, - .owner = THIS_MODULE, }; static int jz4740_pwm_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-keembay.c b/drivers/pwm/pwm-keembay.c index ac02d8bb4a0b5..ac824ecc3f641 100644 --- a/drivers/pwm/pwm-keembay.c +++ b/drivers/pwm/pwm-keembay.c @@ -178,7 +178,6 @@ static int keembay_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, } static const struct pwm_ops keembay_pwm_ops = { - .owner = THIS_MODULE, .apply = keembay_pwm_apply, .get_state = keembay_pwm_get_state, }; diff --git a/drivers/pwm/pwm-lp3943.c b/drivers/pwm/pwm-lp3943.c index 4b133a17f4be3..a1a106747372d 100644 --- a/drivers/pwm/pwm-lp3943.c +++ b/drivers/pwm/pwm-lp3943.c @@ -216,7 +216,6 @@ static const struct pwm_ops lp3943_pwm_ops = { .request = lp3943_pwm_request, .free = lp3943_pwm_free, .apply = lp3943_pwm_apply, - .owner = THIS_MODULE, }; static int lp3943_pwm_parse_dt(struct device *dev, diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c index 7a19a840bca5f..ef7d0da137ede 100644 --- a/drivers/pwm/pwm-lpc18xx-sct.c +++ b/drivers/pwm/pwm-lpc18xx-sct.c @@ -341,7 +341,6 @@ static const struct pwm_ops lpc18xx_pwm_ops = { .apply = lpc18xx_pwm_apply, .request = lpc18xx_pwm_request, .free = lpc18xx_pwm_free, - .owner = THIS_MODULE, }; static const struct of_device_id lpc18xx_pwm_of_match[] = { diff --git a/drivers/pwm/pwm-lpc32xx.c b/drivers/pwm/pwm-lpc32xx.c index 806f0bb3ad6d8..78f664e41e6e3 100644 --- a/drivers/pwm/pwm-lpc32xx.c +++ b/drivers/pwm/pwm-lpc32xx.c @@ -115,7 +115,6 @@ static int lpc32xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops lpc32xx_pwm_ops = { .apply = lpc32xx_pwm_apply, - .owner = THIS_MODULE, }; static int lpc32xx_pwm_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index 23fe332b23947..a6ea3ce7e0196 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -243,7 +243,6 @@ static int pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops pwm_lpss_ops = { .apply = pwm_lpss_apply, .get_state = pwm_lpss_get_state, - .owner = THIS_MODULE, }; struct pwm_lpss_chip *devm_pwm_lpss_probe(struct device *dev, void __iomem *base, diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index 6adb0ed019066..373abfd25acb2 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c @@ -229,7 +229,6 @@ static int pwm_mediatek_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops pwm_mediatek_ops = { .apply = pwm_mediatek_apply, - .owner = THIS_MODULE, }; static int pwm_mediatek_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index 25519cddc2a9d..5bea53243ed2f 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -335,7 +335,6 @@ static const struct pwm_ops meson_pwm_ops = { .free = meson_pwm_free, .apply = meson_pwm_apply, .get_state = meson_pwm_get_state, - .owner = THIS_MODULE, }; static const char * const pwm_meson8b_parent_names[] = { diff --git a/drivers/pwm/pwm-microchip-core.c b/drivers/pwm/pwm-microchip-core.c index e7525c98105eb..c0c53968f3e9d 100644 --- a/drivers/pwm/pwm-microchip-core.c +++ b/drivers/pwm/pwm-microchip-core.c @@ -435,7 +435,6 @@ static int mchp_core_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm static const struct pwm_ops mchp_core_pwm_ops = { .apply = mchp_core_pwm_apply, .get_state = mchp_core_pwm_get_state, - .owner = THIS_MODULE, }; static const struct of_device_id mchp_core_of_match[] = { diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c index a83bd6e18b07f..7748e3eaa8186 100644 --- a/drivers/pwm/pwm-mtk-disp.c +++ b/drivers/pwm/pwm-mtk-disp.c @@ -227,7 +227,6 @@ static int mtk_disp_pwm_get_state(struct pwm_chip *chip, static const struct pwm_ops mtk_disp_pwm_ops = { .apply = mtk_disp_pwm_apply, .get_state = mtk_disp_pwm_get_state, - .owner = THIS_MODULE, }; static int mtk_disp_pwm_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c index 766dbc58dad84..1b5e787d78f1c 100644 --- a/drivers/pwm/pwm-mxs.c +++ b/drivers/pwm/pwm-mxs.c @@ -115,7 +115,6 @@ static int mxs_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops mxs_pwm_ops = { .apply = mxs_pwm_apply, - .owner = THIS_MODULE, }; static int mxs_pwm_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-ntxec.c b/drivers/pwm/pwm-ntxec.c index 7514ea384ec56..78606039eda2e 100644 --- a/drivers/pwm/pwm-ntxec.c +++ b/drivers/pwm/pwm-ntxec.c @@ -126,7 +126,6 @@ static int ntxec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm_dev, } static const struct pwm_ops ntxec_pwm_ops = { - .owner = THIS_MODULE, .apply = ntxec_pwm_apply, /* * No .get_state callback, because the current state cannot be read diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c index 94faa46506866..13161e08dd6eb 100644 --- a/drivers/pwm/pwm-omap-dmtimer.c +++ b/drivers/pwm/pwm-omap-dmtimer.c @@ -311,7 +311,6 @@ static int pwm_omap_dmtimer_apply(struct pwm_chip *chip, static const struct pwm_ops pwm_omap_dmtimer_ops = { .apply = pwm_omap_dmtimer_apply, - .owner = THIS_MODULE, }; static int pwm_omap_dmtimer_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c index 3038a68412a75..e79b1de8c4d83 100644 --- a/drivers/pwm/pwm-pca9685.c +++ b/drivers/pwm/pwm-pca9685.c @@ -505,7 +505,6 @@ static const struct pwm_ops pca9685_pwm_ops = { .get_state = pca9685_pwm_get_state, .request = pca9685_pwm_request, .free = pca9685_pwm_free, - .owner = THIS_MODULE, }; static const struct regmap_config pca9685_regmap_i2c_config = { diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index 1e475ed10180e..faf6b35b93365 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -135,7 +135,6 @@ static int pxa_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops pxa_pwm_ops = { .apply = pxa_pwm_apply, - .owner = THIS_MODULE, }; #ifdef CONFIG_OF diff --git a/drivers/pwm/pwm-raspberrypi-poe.c b/drivers/pwm/pwm-raspberrypi-poe.c index 2939b71a7ba7b..1ad814fdec6bd 100644 --- a/drivers/pwm/pwm-raspberrypi-poe.c +++ b/drivers/pwm/pwm-raspberrypi-poe.c @@ -135,7 +135,6 @@ static int raspberrypi_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops raspberrypi_pwm_ops = { .get_state = raspberrypi_pwm_get_state, .apply = raspberrypi_pwm_apply, - .owner = THIS_MODULE, }; static int raspberrypi_pwm_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c index 5b5f357c44de6..13269f55fccff 100644 --- a/drivers/pwm/pwm-rcar.c +++ b/drivers/pwm/pwm-rcar.c @@ -198,7 +198,6 @@ static const struct pwm_ops rcar_pwm_ops = { .request = rcar_pwm_request, .free = rcar_pwm_free, .apply = rcar_pwm_apply, - .owner = THIS_MODULE, }; static int rcar_pwm_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c index d7311614c846d..1b004e01829a2 100644 --- a/drivers/pwm/pwm-renesas-tpu.c +++ b/drivers/pwm/pwm-renesas-tpu.c @@ -431,7 +431,6 @@ static const struct pwm_ops tpu_pwm_ops = { .request = tpu_pwm_request, .free = tpu_pwm_free, .apply = tpu_pwm_apply, - .owner = THIS_MODULE, }; /* ----------------------------------------------------------------------------- diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c index 03ee18fb82d5b..cce4381e188af 100644 --- a/drivers/pwm/pwm-rockchip.c +++ b/drivers/pwm/pwm-rockchip.c @@ -228,7 +228,6 @@ static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops rockchip_pwm_ops = { .get_state = rockchip_pwm_get_state, .apply = rockchip_pwm_apply, - .owner = THIS_MODULE, }; static const struct rockchip_pwm_data pwm_data_v1 = { diff --git a/drivers/pwm/pwm-rz-mtu3.c b/drivers/pwm/pwm-rz-mtu3.c index a56cecb0e46e3..bdda315b3bd30 100644 --- a/drivers/pwm/pwm-rz-mtu3.c +++ b/drivers/pwm/pwm-rz-mtu3.c @@ -438,7 +438,6 @@ static const struct pwm_ops rz_mtu3_pwm_ops = { .free = rz_mtu3_pwm_free, .get_state = rz_mtu3_pwm_get_state, .apply = rz_mtu3_pwm_apply, - .owner = THIS_MODULE, }; static int rz_mtu3_pwm_pm_runtime_suspend(struct device *dev) diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c index e8828f57ab150..08a9032573836 100644 --- a/drivers/pwm/pwm-samsung.c +++ b/drivers/pwm/pwm-samsung.c @@ -475,7 +475,6 @@ static const struct pwm_ops pwm_samsung_ops = { .request = pwm_samsung_request, .free = pwm_samsung_free, .apply = pwm_samsung_apply, - .owner = THIS_MODULE, }; #ifdef CONFIG_OF diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c index eabddb7c78208..089e50bdbbf01 100644 --- a/drivers/pwm/pwm-sifive.c +++ b/drivers/pwm/pwm-sifive.c @@ -203,7 +203,6 @@ static const struct pwm_ops pwm_sifive_ops = { .free = pwm_sifive_free, .get_state = pwm_sifive_get_state, .apply = pwm_sifive_apply, - .owner = THIS_MODULE, }; static int pwm_sifive_clock_notifier(struct notifier_block *nb, diff --git a/drivers/pwm/pwm-sl28cpld.c b/drivers/pwm/pwm-sl28cpld.c index 9e42e3a74ad6e..88b01ff9e4602 100644 --- a/drivers/pwm/pwm-sl28cpld.c +++ b/drivers/pwm/pwm-sl28cpld.c @@ -200,7 +200,6 @@ static int sl28cpld_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops sl28cpld_pwm_ops = { .apply = sl28cpld_pwm_apply, .get_state = sl28cpld_pwm_get_state, - .owner = THIS_MODULE, }; static int sl28cpld_pwm_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-spear.c b/drivers/pwm/pwm-spear.c index 4e1cfd8d7c037..2cbc34cf6799b 100644 --- a/drivers/pwm/pwm-spear.c +++ b/drivers/pwm/pwm-spear.c @@ -189,7 +189,6 @@ static int spear_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops spear_pwm_ops = { .apply = spear_pwm_apply, - .owner = THIS_MODULE, }; static int spear_pwm_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c index 1499c8c1fe375..dfda2152a7c18 100644 --- a/drivers/pwm/pwm-sprd.c +++ b/drivers/pwm/pwm-sprd.c @@ -210,7 +210,6 @@ static int sprd_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops sprd_pwm_ops = { .apply = sprd_pwm_apply, .get_state = sprd_pwm_get_state, - .owner = THIS_MODULE, }; static int sprd_pwm_clk_init(struct sprd_pwm_chip *spc) diff --git a/drivers/pwm/pwm-sti.c b/drivers/pwm/pwm-sti.c index b1d1373648a38..5756f2e3b3c0b 100644 --- a/drivers/pwm/pwm-sti.c +++ b/drivers/pwm/pwm-sti.c @@ -420,7 +420,6 @@ static const struct pwm_ops sti_pwm_ops = { .capture = sti_pwm_capture, .apply = sti_pwm_apply, .free = sti_pwm_free, - .owner = THIS_MODULE, }; static irqreturn_t sti_pwm_interrupt(int irq, void *data) diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c index bb3a045a73343..b67974cc18725 100644 --- a/drivers/pwm/pwm-stm32-lp.c +++ b/drivers/pwm/pwm-stm32-lp.c @@ -189,7 +189,6 @@ static int stm32_pwm_lp_get_state(struct pwm_chip *chip, } static const struct pwm_ops stm32_pwm_lp_ops = { - .owner = THIS_MODULE, .apply = stm32_pwm_lp_apply, .get_state = stm32_pwm_lp_get_state, }; diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c index 3d6be7749e231..3303a754ea020 100644 --- a/drivers/pwm/pwm-stm32.c +++ b/drivers/pwm/pwm-stm32.c @@ -487,7 +487,6 @@ static int stm32_pwm_apply_locked(struct pwm_chip *chip, struct pwm_device *pwm, } static const struct pwm_ops stm32pwm_ops = { - .owner = THIS_MODULE, .apply = stm32_pwm_apply_locked, .capture = IS_ENABLED(CONFIG_DMA_ENGINE) ? stm32_pwm_capture : NULL, }; diff --git a/drivers/pwm/pwm-stmpe.c b/drivers/pwm/pwm-stmpe.c index e205405c4828b..a46f5b4dd8162 100644 --- a/drivers/pwm/pwm-stmpe.c +++ b/drivers/pwm/pwm-stmpe.c @@ -287,7 +287,6 @@ static int stmpe_24xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops stmpe_24xx_pwm_ops = { .apply = stmpe_24xx_pwm_apply, - .owner = THIS_MODULE, }; static int __init stmpe_pwm_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index c84fcf1a13dc2..1a439025540d4 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -325,7 +325,6 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops sun4i_pwm_ops = { .apply = sun4i_pwm_apply, .get_state = sun4i_pwm_get_state, - .owner = THIS_MODULE, }; static const struct sun4i_pwm_data sun4i_pwm_dual_nobypass = { diff --git a/drivers/pwm/pwm-sunplus.c b/drivers/pwm/pwm-sunplus.c index 7705c7b86c3a3..773e2f80526e8 100644 --- a/drivers/pwm/pwm-sunplus.c +++ b/drivers/pwm/pwm-sunplus.c @@ -163,7 +163,6 @@ static int sunplus_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops sunplus_pwm_ops = { .apply = sunplus_pwm_apply, .get_state = sunplus_pwm_get_state, - .owner = THIS_MODULE, }; static void sunplus_pwm_clk_release(void *data) diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index a169a34e07781..39ea51e08c946 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -268,7 +268,6 @@ static int tegra_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops tegra_pwm_ops = { .apply = tegra_pwm_apply, - .owner = THIS_MODULE, }; static int tegra_pwm_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c index 8c94b266c1b2a..11e3549cf1034 100644 --- a/drivers/pwm/pwm-tiecap.c +++ b/drivers/pwm/pwm-tiecap.c @@ -205,7 +205,6 @@ static int ecap_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops ecap_pwm_ops = { .apply = ecap_pwm_apply, - .owner = THIS_MODULE, }; static const struct of_device_id ecap_of_match[] = { diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index ecbfd7e954ecb..66ac2655845f7 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -437,7 +437,6 @@ static int ehrpwm_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops ehrpwm_pwm_ops = { .free = ehrpwm_pwm_free, .apply = ehrpwm_pwm_apply, - .owner = THIS_MODULE, }; static const struct of_device_id ehrpwm_of_match[] = { diff --git a/drivers/pwm/pwm-twl-led.c b/drivers/pwm/pwm-twl-led.c index 8fb84b4418538..625233f4703a9 100644 --- a/drivers/pwm/pwm-twl-led.c +++ b/drivers/pwm/pwm-twl-led.c @@ -189,7 +189,6 @@ static int twl4030_pwmled_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops twl4030_pwmled_ops = { .apply = twl4030_pwmled_apply, - .owner = THIS_MODULE, }; static int twl6030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm, @@ -342,7 +341,6 @@ static const struct pwm_ops twl6030_pwmled_ops = { .apply = twl6030_pwmled_apply, .request = twl6030_pwmled_request, .free = twl6030_pwmled_free, - .owner = THIS_MODULE, }; static int twl_pwmled_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-twl.c b/drivers/pwm/pwm-twl.c index 86567add79dbe..603d31f27470f 100644 --- a/drivers/pwm/pwm-twl.c +++ b/drivers/pwm/pwm-twl.c @@ -333,12 +333,10 @@ static const struct pwm_ops twl4030_pwm_ops = { .apply = twl4030_pwm_apply, .request = twl4030_pwm_request, .free = twl4030_pwm_free, - .owner = THIS_MODULE, }; static const struct pwm_ops twl6030_pwm_ops = { .apply = twl6030_pwm_apply, - .owner = THIS_MODULE, }; static int twl_pwm_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-visconti.c b/drivers/pwm/pwm-visconti.c index 7f7591a2384c5..8d736d5581221 100644 --- a/drivers/pwm/pwm-visconti.c +++ b/drivers/pwm/pwm-visconti.c @@ -129,7 +129,6 @@ static int visconti_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops visconti_pwm_ops = { .apply = visconti_pwm_apply, .get_state = visconti_pwm_get_state, - .owner = THIS_MODULE, }; static int visconti_pwm_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c index 6d46db51daacc..a96c7f5d90999 100644 --- a/drivers/pwm/pwm-vt8500.c +++ b/drivers/pwm/pwm-vt8500.c @@ -221,7 +221,6 @@ static int vt8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops vt8500_pwm_ops = { .apply = vt8500_pwm_apply, - .owner = THIS_MODULE, }; static const struct of_device_id vt8500_pwm_dt_ids[] = { diff --git a/drivers/pwm/pwm-xilinx.c b/drivers/pwm/pwm-xilinx.c index 85153ee90809c..5f3c2a6fed11c 100644 --- a/drivers/pwm/pwm-xilinx.c +++ b/drivers/pwm/pwm-xilinx.c @@ -198,7 +198,6 @@ static int xilinx_pwm_get_state(struct pwm_chip *chip, static const struct pwm_ops xilinx_pwm_ops = { .apply = xilinx_pwm_apply, .get_state = xilinx_pwm_get_state, - .owner = THIS_MODULE, }; static const struct regmap_config xilinx_pwm_regmap_config = { diff --git a/drivers/staging/greybus/pwm.c b/drivers/staging/greybus/pwm.c index 57cc1960d0598..a3cb68cfa0f9b 100644 --- a/drivers/staging/greybus/pwm.c +++ b/drivers/staging/greybus/pwm.c @@ -258,7 +258,6 @@ static const struct pwm_ops gb_pwm_ops = { .request = gb_pwm_request, .free = gb_pwm_free, .apply = gb_pwm_apply, - .owner = THIS_MODULE, }; static int gb_pwm_probe(struct gbphy_device *gbphy_dev, diff --git a/include/linux/pwm.h b/include/linux/pwm.h index d2f9f690a9c14..56e3b7a09824a 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -267,7 +267,6 @@ struct pwm_capture { * @get_state: get the current PWM state. This function is only * called once per PWM device when the PWM chip is * registered. - * @owner: helps prevent removal of modules exporting active PWMs */ struct pwm_ops { int (*request)(struct pwm_chip *chip, struct pwm_device *pwm); @@ -278,13 +277,13 @@ struct pwm_ops { const struct pwm_state *state); int (*get_state)(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_state *state); - struct module *owner; }; /** * struct pwm_chip - abstract a PWM controller * @dev: device providing the PWMs * @ops: callbacks for this PWM controller + * @owner: module providing this chip * @base: number of first PWM controlled by this chip * @npwm: number of PWMs controlled by this chip * @of_xlate: request a PWM device given a device tree PWM specifier @@ -295,6 +294,7 @@ struct pwm_ops { struct pwm_chip { struct device *dev; const struct pwm_ops *ops; + struct module *owner; int base; unsigned int npwm; @@ -386,10 +386,12 @@ int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result, int pwm_set_chip_data(struct pwm_device *pwm, void *data); void *pwm_get_chip_data(struct pwm_device *pwm); -int pwmchip_add(struct pwm_chip *chip); +int __pwmchip_add(struct pwm_chip *chip, struct module *owner); +#define pwmchip_add(chip) __pwmchip_add(chip, THIS_MODULE) void pwmchip_remove(struct pwm_chip *chip); -int devm_pwmchip_add(struct device *dev, struct pwm_chip *chip); +int __devm_pwmchip_add(struct device *dev, struct pwm_chip *chip, struct module *owner); +#define devm_pwmchip_add(dev, chip) __devm_pwmchip_add(dev, chip, THIS_MODULE) struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, unsigned int index, -- GitLab From 91a69d38cf97b195fef1a10ea53cf429aa134497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 4 Aug 2023 16:27:07 +0200 Subject: [PATCH 0581/1451] pwm: crc: Allow compilation as module and with COMPILE_TEST MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver compiles just fine as a module. The parent driver's Kconfig symbol already depends on X86 || COMPILE_TEST, so X86 can just be dropped from the dependencies allowing compilation on other platforms than x86. Link: https://lore.kernel.org/r/20230804142707.412137-3-u.kleine-koenig@pengutronix.de Reviewed-by: Linus Walleij Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/Kconfig | 4 ++-- drivers/pwm/pwm-crc.c | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 502d041d4a11e..ce22b1f311f5a 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -173,8 +173,8 @@ config PWM_CLPS711X will be called pwm-clps711x. config PWM_CRC - bool "Intel Crystalcove (CRC) PWM support" - depends on X86 && INTEL_SOC_PMIC + tristate "Intel Crystalcove (CRC) PWM support" + depends on INTEL_SOC_PMIC help Generic PWM framework driver for Crystalcove (CRC) PMIC based PWM control. diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c index b9f063dc6b5fd..2b0b659eee979 100644 --- a/drivers/pwm/pwm-crc.c +++ b/drivers/pwm/pwm-crc.c @@ -184,5 +184,8 @@ static struct platform_driver crystalcove_pwm_driver = { .name = "crystal_cove_pwm", }, }; +module_platform_driver(crystalcove_pwm_driver); -builtin_platform_driver(crystalcove_pwm_driver); +MODULE_ALIAS("platform:crystal_cove_pwm"); +MODULE_DESCRIPTION("Intel Crystalcove (CRC) PWM support"); +MODULE_LICENSE("GPL"); -- GitLab From 1b2af7bb7523a86d0ab1f1a5e8d65063d08c7856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 5 Jul 2023 10:06:43 +0200 Subject: [PATCH 0582/1451] pwm: berlin: Put per-channel config into driver data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of allocating extra data in .request() provide the needed memory in struct berlin_pwm_chip. This reduces the number of allocations. A side effect is that on suspend and resume the state for all four channels is always saved and restored. This is easier (and probably quicker) than looking up the matching pwm_device and checking its PWMF_REQUESTED bit. Link: https://lore.kernel.org/r/20230705080650.2353391-2-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-berlin.c | 37 ++++++------------------------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c index 6a6641fc4fa1b..832cb5995d18d 100644 --- a/drivers/pwm/pwm-berlin.c +++ b/drivers/pwm/pwm-berlin.c @@ -39,6 +39,8 @@ #define BERLIN_PWM_TCNT 0xc #define BERLIN_PWM_MAX_TCNT 65535 +#define BERLIN_PWM_NUMPWMS 4 + struct berlin_pwm_channel { u32 enable; u32 ctrl; @@ -50,6 +52,7 @@ struct berlin_pwm_chip { struct pwm_chip chip; struct clk *clk; void __iomem *base; + struct berlin_pwm_channel channel[BERLIN_PWM_NUMPWMS]; }; static inline struct berlin_pwm_chip *to_berlin_pwm_chip(struct pwm_chip *chip) @@ -70,24 +73,6 @@ static inline void berlin_pwm_writel(struct berlin_pwm_chip *bpc, writel_relaxed(value, bpc->base + channel * 0x10 + offset); } -static int berlin_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct berlin_pwm_channel *channel; - - channel = kzalloc(sizeof(*channel), GFP_KERNEL); - if (!channel) - return -ENOMEM; - - return pwm_set_chip_data(pwm, channel); -} - -static void berlin_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct berlin_pwm_channel *channel = pwm_get_chip_data(pwm); - - kfree(channel); -} - static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, u64 duty_ns, u64 period_ns) { @@ -202,8 +187,6 @@ static int berlin_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, } static const struct pwm_ops berlin_pwm_ops = { - .request = berlin_pwm_request, - .free = berlin_pwm_free, .apply = berlin_pwm_apply, }; @@ -236,7 +219,7 @@ static int berlin_pwm_probe(struct platform_device *pdev) bpc->chip.dev = &pdev->dev; bpc->chip.ops = &berlin_pwm_ops; - bpc->chip.npwm = 4; + bpc->chip.npwm = BERLIN_PWM_NUMPWMS; ret = pwmchip_add(&bpc->chip); if (ret < 0) { @@ -266,11 +249,7 @@ static int berlin_pwm_suspend(struct device *dev) unsigned int i; for (i = 0; i < bpc->chip.npwm; i++) { - struct berlin_pwm_channel *channel; - - channel = pwm_get_chip_data(&bpc->chip.pwms[i]); - if (!channel) - continue; + struct berlin_pwm_channel *channel = &bpc->channel[i]; channel->enable = berlin_pwm_readl(bpc, i, BERLIN_PWM_ENABLE); channel->ctrl = berlin_pwm_readl(bpc, i, BERLIN_PWM_CONTROL); @@ -294,11 +273,7 @@ static int berlin_pwm_resume(struct device *dev) return ret; for (i = 0; i < bpc->chip.npwm; i++) { - struct berlin_pwm_channel *channel; - - channel = pwm_get_chip_data(&bpc->chip.pwms[i]); - if (!channel) - continue; + struct berlin_pwm_channel *channel = &bpc->channel[i]; berlin_pwm_writel(bpc, i, channel->ctrl, BERLIN_PWM_CONTROL); berlin_pwm_writel(bpc, i, channel->duty, BERLIN_PWM_DUTY); -- GitLab From e3fe982b2e4e968126a61c14df6c6a50fd7db2a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 5 Jul 2023 10:06:44 +0200 Subject: [PATCH 0583/1451] pwm: samsung: Put per-channel data into driver data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of allocating extra data in .request() provide the needed memory in struct samsung_pwm_chip. This reduces the number of allocations. Even though now all 5 channel structs are allocated this is probably outweighed by the reduced overhead to track up to 6 smaller allocations. Link: https://lore.kernel.org/r/20230705080650.2353391-3-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-samsung.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c index 08a9032573836..c437fab7ded88 100644 --- a/drivers/pwm/pwm-samsung.c +++ b/drivers/pwm/pwm-samsung.c @@ -88,6 +88,7 @@ struct samsung_pwm_chip { struct clk *base_clk; struct clk *tclk0; struct clk *tclk1; + struct samsung_pwm_channel channel[SAMSUNG_PWM_NUM]; }; #ifndef CONFIG_CLKSRC_SAMSUNG_PWM @@ -228,7 +229,6 @@ static unsigned long pwm_samsung_calc_tin(struct samsung_pwm_chip *chip, static int pwm_samsung_request(struct pwm_chip *chip, struct pwm_device *pwm) { struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip); - struct samsung_pwm_channel *our_chan; if (!(our_chip->variant.output_mask & BIT(pwm->hwpwm))) { dev_warn(chip->dev, @@ -237,20 +237,11 @@ static int pwm_samsung_request(struct pwm_chip *chip, struct pwm_device *pwm) return -EINVAL; } - our_chan = kzalloc(sizeof(*our_chan), GFP_KERNEL); - if (!our_chan) - return -ENOMEM; - - pwm_set_chip_data(pwm, our_chan); + memset(&our_chip->channel[pwm->hwpwm], 0, sizeof(our_chip->channel[pwm->hwpwm])); return 0; } -static void pwm_samsung_free(struct pwm_chip *chip, struct pwm_device *pwm) -{ - kfree(pwm_get_chip_data(pwm)); -} - static int pwm_samsung_enable(struct pwm_chip *chip, struct pwm_device *pwm) { struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip); @@ -318,7 +309,7 @@ static int __pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns, bool force_period) { struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip); - struct samsung_pwm_channel *chan = pwm_get_chip_data(pwm); + struct samsung_pwm_channel *chan = &our_chip->channel[pwm->hwpwm]; u32 tin_ns = chan->tin_ns, tcnt, tcmp, oldtcmp; tcnt = readl(our_chip->base + REG_TCNTB(pwm->hwpwm)); @@ -473,7 +464,6 @@ static int pwm_samsung_apply(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops pwm_samsung_ops = { .request = pwm_samsung_request, - .free = pwm_samsung_free, .apply = pwm_samsung_apply, }; @@ -638,9 +628,9 @@ static int pwm_samsung_resume(struct device *dev) for (i = 0; i < SAMSUNG_PWM_NUM; i++) { struct pwm_device *pwm = &chip->pwms[i]; - struct samsung_pwm_channel *chan = pwm_get_chip_data(pwm); + struct samsung_pwm_channel *chan = &our_chip->channel[i]; - if (!chan) + if (!(pwm->flags & PWMF_REQUESTED)) continue; if (our_chip->variant.output_mask & BIT(i)) -- GitLab From 89c8de78cea3119dab28830fb5dcc663ede587c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 5 Jul 2023 10:06:45 +0200 Subject: [PATCH 0584/1451] pwm: jz4740: Put per-channel clk into driver data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop using chip_data which is about to go away. Instead track the per-channel clk in struct jz4740_pwm_chip. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Paul Cercueil Link: https://lore.kernel.org/r/20230705080650.2353391-4-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-jz4740.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c index 49a6e28d1d986..e9375de60ad62 100644 --- a/drivers/pwm/pwm-jz4740.c +++ b/drivers/pwm/pwm-jz4740.c @@ -27,6 +27,7 @@ struct soc_info { struct jz4740_pwm_chip { struct pwm_chip chip; struct regmap *map; + struct clk *clk[]; }; static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip) @@ -70,14 +71,15 @@ static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) return err; } - pwm_set_chip_data(pwm, clk); + jz->clk[pwm->hwpwm] = clk; return 0; } static void jz4740_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) { - struct clk *clk = pwm_get_chip_data(pwm); + struct jz4740_pwm_chip *jz = to_jz4740(chip); + struct clk *clk = jz->clk[pwm->hwpwm]; clk_disable_unprepare(clk); clk_put(clk); @@ -123,7 +125,7 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, { struct jz4740_pwm_chip *jz = to_jz4740(pwm->chip); unsigned long long tmp = 0xffffull * NSEC_PER_SEC; - struct clk *clk = pwm_get_chip_data(pwm); + struct clk *clk = jz->clk[pwm->hwpwm]; unsigned long period, duty; long rate; int err; @@ -228,7 +230,8 @@ static int jz4740_pwm_probe(struct platform_device *pdev) if (!info) return -EINVAL; - jz = devm_kzalloc(dev, sizeof(*jz), GFP_KERNEL); + jz = devm_kzalloc(dev, struct_size(jz, clk, info->num_pwms), + GFP_KERNEL); if (!jz) return -ENOMEM; -- GitLab From 06cc4767750337ad162a0a7bcfd6f6eff6e0fe92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 5 Jul 2023 10:06:46 +0200 Subject: [PATCH 0585/1451] pwm: lp3943: Drop usage of pwm_[gs]et_chip_data() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of distributing the driver's bookkeeping over 3 (i.e. LP3943_NUM_PWMS + 1) separately allocated memory chunks, put all together in struct lp3943_pwm. This reduces the number of memory allocations and so fragmentation and maybe even the number of cache misses. Also &lp3943_pwm->pwm_map[pwm->hwpwm] is cheaper to evaluate than pwm_get_chip_data(pwm) as the former is just an addition in machine code while the latter involves a function call. Link: https://lore.kernel.org/r/20230705080650.2353391-5-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-lp3943.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/pwm/pwm-lp3943.c b/drivers/pwm/pwm-lp3943.c index a1a106747372d..32350a357278d 100644 --- a/drivers/pwm/pwm-lp3943.c +++ b/drivers/pwm/pwm-lp3943.c @@ -23,6 +23,7 @@ struct lp3943_pwm { struct pwm_chip chip; struct lp3943 *lp3943; struct lp3943_platform_data *pdata; + struct lp3943_pwm_map pwm_map[LP3943_NUM_PWMS]; }; static inline struct lp3943_pwm *to_lp3943_pwm(struct pwm_chip *chip) @@ -35,13 +36,9 @@ lp3943_pwm_request_map(struct lp3943_pwm *lp3943_pwm, int hwpwm) { struct lp3943_platform_data *pdata = lp3943_pwm->pdata; struct lp3943 *lp3943 = lp3943_pwm->lp3943; - struct lp3943_pwm_map *pwm_map; + struct lp3943_pwm_map *pwm_map = &lp3943_pwm->pwm_map[hwpwm]; int i, offset; - pwm_map = kzalloc(sizeof(*pwm_map), GFP_KERNEL); - if (!pwm_map) - return ERR_PTR(-ENOMEM); - pwm_map->output = pdata->pwms[hwpwm]->output; pwm_map->num_outputs = pdata->pwms[hwpwm]->num_outputs; @@ -49,10 +46,8 @@ lp3943_pwm_request_map(struct lp3943_pwm *lp3943_pwm, int hwpwm) offset = pwm_map->output[i]; /* Return an error if the pin is already assigned */ - if (test_and_set_bit(offset, &lp3943->pin_used)) { - kfree(pwm_map); + if (test_and_set_bit(offset, &lp3943->pin_used)) return ERR_PTR(-EBUSY); - } } return pwm_map; @@ -67,7 +62,7 @@ static int lp3943_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) if (IS_ERR(pwm_map)) return PTR_ERR(pwm_map); - return pwm_set_chip_data(pwm, pwm_map); + return 0; } static void lp3943_pwm_free_map(struct lp3943_pwm *lp3943_pwm, @@ -80,14 +75,12 @@ static void lp3943_pwm_free_map(struct lp3943_pwm *lp3943_pwm, offset = pwm_map->output[i]; clear_bit(offset, &lp3943->pin_used); } - - kfree(pwm_map); } static void lp3943_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) { struct lp3943_pwm *lp3943_pwm = to_lp3943_pwm(chip); - struct lp3943_pwm_map *pwm_map = pwm_get_chip_data(pwm); + struct lp3943_pwm_map *pwm_map = &lp3943_pwm->pwm_map[pwm->hwpwm]; lp3943_pwm_free_map(lp3943_pwm, pwm_map); } @@ -159,7 +152,7 @@ static int lp3943_pwm_set_mode(struct lp3943_pwm *lp3943_pwm, static int lp3943_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) { struct lp3943_pwm *lp3943_pwm = to_lp3943_pwm(chip); - struct lp3943_pwm_map *pwm_map = pwm_get_chip_data(pwm); + struct lp3943_pwm_map *pwm_map = &lp3943_pwm->pwm_map[pwm->hwpwm]; u8 val; if (pwm->hwpwm == 0) @@ -178,7 +171,7 @@ static int lp3943_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) static void lp3943_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) { struct lp3943_pwm *lp3943_pwm = to_lp3943_pwm(chip); - struct lp3943_pwm_map *pwm_map = pwm_get_chip_data(pwm); + struct lp3943_pwm_map *pwm_map = &lp3943_pwm->pwm_map[pwm->hwpwm]; /* * LP3943 outputs are open-drain, so the pin should be configured -- GitLab From ec63391a0d402cafa5f4dfd11e05cd325ae7e2f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 5 Jul 2023 10:06:47 +0200 Subject: [PATCH 0586/1451] pwm: renesas: Drop usage of pwm_[gs]et_chip_data() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of distributing the driver's bookkeeping over 5 (i.e. TPU_CHANNEL_MAX + 1) separately allocated memory chunks, put all together in struct tpu_device. This reduces the number of memory allocations and so fragmentation and maybe even the number of cache misses. Also &tpu->tpd[pwm->hwpwm] is cheaper to evaluate than pwm_get_chip_data(pwm) as the former is just an addition in machine code while the latter involves a function call. Link: https://lore.kernel.org/r/20230705080650.2353391-6-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-renesas-tpu.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c index 1b004e01829a2..4239f2c3e8b2a 100644 --- a/drivers/pwm/pwm-renesas-tpu.c +++ b/drivers/pwm/pwm-renesas-tpu.c @@ -85,6 +85,7 @@ struct tpu_device { void __iomem *base; struct clk *clk; + struct tpu_pwm_device tpd[TPU_CHANNEL_MAX]; }; #define to_tpu_device(c) container_of(c, struct tpu_device, chip) @@ -215,9 +216,7 @@ static int tpu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) if (pwm->hwpwm >= TPU_CHANNEL_MAX) return -EINVAL; - tpd = kzalloc(sizeof(*tpd), GFP_KERNEL); - if (tpd == NULL) - return -ENOMEM; + tpd = &tpu->tpd[pwm->hwpwm]; tpd->tpu = tpu; tpd->channel = pwm->hwpwm; @@ -228,24 +227,22 @@ static int tpu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) tpd->timer_on = false; - pwm_set_chip_data(pwm, tpd); - return 0; } static void tpu_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) { - struct tpu_pwm_device *tpd = pwm_get_chip_data(pwm); + struct tpu_device *tpu = to_tpu_device(chip); + struct tpu_pwm_device *tpd = &tpu->tpd[pwm->hwpwm]; tpu_pwm_timer_stop(tpd); - kfree(tpd); } static int tpu_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, u64 duty_ns, u64 period_ns, bool enabled) { - struct tpu_pwm_device *tpd = pwm_get_chip_data(pwm); struct tpu_device *tpu = to_tpu_device(chip); + struct tpu_pwm_device *tpd = &tpu->tpd[pwm->hwpwm]; unsigned int prescaler; bool duty_only = false; u32 clk_rate; @@ -353,7 +350,8 @@ static int tpu_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, static int tpu_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, enum pwm_polarity polarity) { - struct tpu_pwm_device *tpd = pwm_get_chip_data(pwm); + struct tpu_device *tpu = to_tpu_device(chip); + struct tpu_pwm_device *tpd = &tpu->tpd[pwm->hwpwm]; tpd->polarity = polarity; @@ -362,7 +360,8 @@ static int tpu_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, static int tpu_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) { - struct tpu_pwm_device *tpd = pwm_get_chip_data(pwm); + struct tpu_device *tpu = to_tpu_device(chip); + struct tpu_pwm_device *tpd = &tpu->tpd[pwm->hwpwm]; int ret; ret = tpu_pwm_timer_start(tpd); @@ -384,7 +383,8 @@ static int tpu_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) static void tpu_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) { - struct tpu_pwm_device *tpd = pwm_get_chip_data(pwm); + struct tpu_device *tpu = to_tpu_device(chip); + struct tpu_pwm_device *tpd = &tpu->tpd[pwm->hwpwm]; /* The timer must be running to modify the pin output configuration. */ tpu_pwm_timer_start(tpd); -- GitLab From 2d6812b41e0d832919d72c72ebddf361df53ba1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 5 Jul 2023 10:06:48 +0200 Subject: [PATCH 0587/1451] pwm: sti: Reduce number of allocations and drop usage of chip_data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using one allocation per capture channel, use a single one. Also store it in driver data instead of chip data. This has several advantages: - driver data isn't cleared when pwm_put() is called - Reduces memory fragmentation Also register the pwm chip only after the per capture channel data is initialized as the capture callback relies on this initialization and it might be called even before pwmchip_add() returns. It would be still better to have struct sti_pwm_compat_data and the per-channel data struct sti_cpt_ddata in a single memory chunk, but that's not easily possible because the number of capture channels isn't known yet when the driver data struct is allocated. Fixes: e926b12c611c ("pwm: Clear chip_data in pwm_put()") Reported-by: George Stark Fixes: c97267ae831d ("pwm: sti: Add PWM capture callback") Link: https://lore.kernel.org/r/20230705080650.2353391-7-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-sti.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/pwm/pwm-sti.c b/drivers/pwm/pwm-sti.c index 5756f2e3b3c0b..dc92cea31cd07 100644 --- a/drivers/pwm/pwm-sti.c +++ b/drivers/pwm/pwm-sti.c @@ -79,6 +79,7 @@ struct sti_pwm_compat_data { unsigned int cpt_num_devs; unsigned int max_pwm_cnt; unsigned int max_prescale; + struct sti_cpt_ddata *ddata; }; struct sti_pwm_chip { @@ -314,7 +315,7 @@ static int sti_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm, { struct sti_pwm_chip *pc = to_sti_pwmchip(chip); struct sti_pwm_compat_data *cdata = pc->cdata; - struct sti_cpt_ddata *ddata = pwm_get_chip_data(pwm); + struct sti_cpt_ddata *ddata = &cdata->ddata[pwm->hwpwm]; struct device *dev = pc->dev; unsigned int effective_ticks; unsigned long long high, low; @@ -439,7 +440,7 @@ static irqreturn_t sti_pwm_interrupt(int irq, void *data) while (cpt_int_stat) { devicenum = ffs(cpt_int_stat) - 1; - ddata = pwm_get_chip_data(&pc->chip.pwms[devicenum]); + ddata = &pc->cdata->ddata[devicenum]; /* * Capture input: @@ -637,30 +638,28 @@ static int sti_pwm_probe(struct platform_device *pdev) dev_err(dev, "failed to prepare clock\n"); return ret; } + + cdata->ddata = devm_kzalloc(dev, cdata->cpt_num_devs * sizeof(*cdata->ddata), GFP_KERNEL); + if (!cdata->ddata) + return -ENOMEM; } pc->chip.dev = dev; pc->chip.ops = &sti_pwm_ops; pc->chip.npwm = pc->cdata->pwm_num_devs; - ret = pwmchip_add(&pc->chip); - if (ret < 0) { - clk_unprepare(pc->pwm_clk); - clk_unprepare(pc->cpt_clk); - return ret; - } - for (i = 0; i < cdata->cpt_num_devs; i++) { - struct sti_cpt_ddata *ddata; - - ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); - if (!ddata) - return -ENOMEM; + struct sti_cpt_ddata *ddata = &cdata->ddata[i]; init_waitqueue_head(&ddata->wait); mutex_init(&ddata->lock); + } - pwm_set_chip_data(&pc->chip.pwms[i], ddata); + ret = pwmchip_add(&pc->chip); + if (ret < 0) { + clk_unprepare(pc->pwm_clk); + clk_unprepare(pc->cpt_clk); + return ret; } platform_set_drvdata(pdev, pc); -- GitLab From 82adc1b2688b02a6b556720d9954a16a4129567f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 5 Jul 2023 10:06:49 +0200 Subject: [PATCH 0588/1451] pwm: cros-ec: Put per-channel data into driver data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of an allocation of a single u16 per channel, allocate them all in a single chunk which greatly reduces memory fragmentation and also the overhead to track the allocated memory. Also put the channel data in driver data where it's cheaper to determine the address (no function call involved, just a trivial pointer addition). This also allows to get rid of the request and free callbacks. The only cost is that the channel data is allocated early, and even for unused channels. Reviewed-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20230705080650.2353391-8-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-cros-ec.c | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c index 500504c7d459b..5ab84e0cb9111 100644 --- a/drivers/pwm/pwm-cros-ec.c +++ b/drivers/pwm/pwm-cros-ec.c @@ -22,12 +22,14 @@ * @ec: Pointer to EC device * @chip: PWM controller chip * @use_pwm_type: Use PWM types instead of generic channels + * @channel: array with per-channel data */ struct cros_ec_pwm_device { struct device *dev; struct cros_ec_device *ec; struct pwm_chip chip; bool use_pwm_type; + struct cros_ec_pwm *channel; }; /** @@ -43,26 +45,6 @@ static inline struct cros_ec_pwm_device *pwm_to_cros_ec_pwm(struct pwm_chip *chi return container_of(chip, struct cros_ec_pwm_device, chip); } -static int cros_ec_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct cros_ec_pwm *channel; - - channel = kzalloc(sizeof(*channel), GFP_KERNEL); - if (!channel) - return -ENOMEM; - - pwm_set_chip_data(pwm, channel); - - return 0; -} - -static void cros_ec_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct cros_ec_pwm *channel = pwm_get_chip_data(pwm); - - kfree(channel); -} - static int cros_ec_dt_type_to_pwm_type(u8 dt_index, u8 *pwm_type) { switch (dt_index) { @@ -158,7 +140,7 @@ static int cros_ec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state) { struct cros_ec_pwm_device *ec_pwm = pwm_to_cros_ec_pwm(chip); - struct cros_ec_pwm *channel = pwm_get_chip_data(pwm); + struct cros_ec_pwm *channel = &ec_pwm->channel[pwm->hwpwm]; u16 duty_cycle; int ret; @@ -188,7 +170,7 @@ static int cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_state *state) { struct cros_ec_pwm_device *ec_pwm = pwm_to_cros_ec_pwm(chip); - struct cros_ec_pwm *channel = pwm_get_chip_data(pwm); + struct cros_ec_pwm *channel = &ec_pwm->channel[pwm->hwpwm]; int ret; ret = cros_ec_pwm_get_duty(ec_pwm, pwm->hwpwm); @@ -237,8 +219,6 @@ cros_ec_pwm_xlate(struct pwm_chip *chip, const struct of_phandle_args *args) } static const struct pwm_ops cros_ec_pwm_ops = { - .request = cros_ec_pwm_request, - .free = cros_ec_pwm_free, .get_state = cros_ec_pwm_get_state, .apply = cros_ec_pwm_apply, }; @@ -316,6 +296,11 @@ static int cros_ec_pwm_probe(struct platform_device *pdev) chip->npwm = ret; } + ec_pwm->channel = devm_kcalloc(dev, chip->npwm, sizeof(*ec_pwm->channel), + GFP_KERNEL); + if (!ec_pwm->channel) + return -ENOMEM; + dev_dbg(dev, "Probed %u PWMs\n", chip->npwm); ret = pwmchip_add(chip); -- GitLab From a6e5654e0b8b53e2d0e316bc7cecb81dd8371f18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 5 Jul 2023 10:06:50 +0200 Subject: [PATCH 0589/1451] pwm: Drop pwm_[sg]et_chip_data() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The semantic of chip_data is a bit surprising as it's cleared when pwm_put() is called. Also there is a big overlap with the standard driver data. All drivers were adapted to not make use of chip_data any more, so it can go away. Link: https://lore.kernel.org/r/20230705080650.2353391-9-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 31 ------------------------------- include/linux/pwm.h | 14 -------------- 2 files changed, 45 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index a2824eb4e236d..29078486534d4 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -208,36 +208,6 @@ static void of_pwmchip_remove(struct pwm_chip *chip) of_node_put(chip->dev->of_node); } -/** - * pwm_set_chip_data() - set private chip data for a PWM - * @pwm: PWM device - * @data: pointer to chip-specific data - * - * Returns: 0 on success or a negative error code on failure. - */ -int pwm_set_chip_data(struct pwm_device *pwm, void *data) -{ - if (!pwm) - return -EINVAL; - - pwm->chip_data = data; - - return 0; -} -EXPORT_SYMBOL_GPL(pwm_set_chip_data); - -/** - * pwm_get_chip_data() - get private chip data for a PWM - * @pwm: PWM device - * - * Returns: A pointer to the chip-private data for the PWM device. - */ -void *pwm_get_chip_data(struct pwm_device *pwm) -{ - return pwm ? pwm->chip_data : NULL; -} -EXPORT_SYMBOL_GPL(pwm_get_chip_data); - static bool pwm_ops_check(const struct pwm_chip *chip) { const struct pwm_ops *ops = chip->ops; @@ -980,7 +950,6 @@ void pwm_put(struct pwm_device *pwm) if (pwm->chip->ops->free) pwm->chip->ops->free(pwm->chip, pwm); - pwm_set_chip_data(pwm, NULL); pwm->label = NULL; module_put(pwm->chip->owner); diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 56e3b7a09824a..e3b437587b32d 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -71,7 +71,6 @@ struct pwm_state { * @hwpwm: per-chip relative index of the PWM device * @pwm: global index of the PWM device * @chip: PWM chip providing this PWM device - * @chip_data: chip-private data associated with the PWM device * @args: PWM arguments * @state: last applied state * @last: last implemented state (for PWM_DEBUG) @@ -82,7 +81,6 @@ struct pwm_device { unsigned int hwpwm; unsigned int pwm; struct pwm_chip *chip; - void *chip_data; struct pwm_args args; struct pwm_state state; @@ -383,8 +381,6 @@ static inline void pwm_disable(struct pwm_device *pwm) /* PWM provider APIs */ int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result, unsigned long timeout); -int pwm_set_chip_data(struct pwm_device *pwm, void *data); -void *pwm_get_chip_data(struct pwm_device *pwm); int __pwmchip_add(struct pwm_chip *chip, struct module *owner); #define pwmchip_add(chip) __pwmchip_add(chip, THIS_MODULE) @@ -447,16 +443,6 @@ static inline int pwm_capture(struct pwm_device *pwm, return -EINVAL; } -static inline int pwm_set_chip_data(struct pwm_device *pwm, void *data) -{ - return -EINVAL; -} - -static inline void *pwm_get_chip_data(struct pwm_device *pwm) -{ - return NULL; -} - static inline int pwmchip_add(struct pwm_chip *chip) { return -EINVAL; -- GitLab From 6dbf23f5cfff789ee7c75a79709f06bcb3c6fc20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 18 Jul 2023 19:55:45 +0200 Subject: [PATCH 0590/1451] pwm: berlin: Simplify using devm functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With devm_clk_get_enabled() the call to clk_disable_unprepare() can be dropped from the error path and the remove callback. With devm_pwmchip_add() pwmchip_remove() can be dropped. Then the remove callback is empty and can go away, too. Link: https://lore.kernel.org/r/20230718175545.3946935-1-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-berlin.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c index 832cb5995d18d..ba2d799917695 100644 --- a/drivers/pwm/pwm-berlin.c +++ b/drivers/pwm/pwm-berlin.c @@ -209,39 +209,23 @@ static int berlin_pwm_probe(struct platform_device *pdev) if (IS_ERR(bpc->base)) return PTR_ERR(bpc->base); - bpc->clk = devm_clk_get(&pdev->dev, NULL); + bpc->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(bpc->clk)) return PTR_ERR(bpc->clk); - ret = clk_prepare_enable(bpc->clk); - if (ret) - return ret; - bpc->chip.dev = &pdev->dev; bpc->chip.ops = &berlin_pwm_ops; bpc->chip.npwm = BERLIN_PWM_NUMPWMS; - ret = pwmchip_add(&bpc->chip); - if (ret < 0) { - dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); - clk_disable_unprepare(bpc->clk); - return ret; - } + ret = devm_pwmchip_add(&pdev->dev, &bpc->chip); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n"); platform_set_drvdata(pdev, bpc); return 0; } -static void berlin_pwm_remove(struct platform_device *pdev) -{ - struct berlin_pwm_chip *bpc = platform_get_drvdata(pdev); - - pwmchip_remove(&bpc->chip); - - clk_disable_unprepare(bpc->clk); -} - #ifdef CONFIG_PM_SLEEP static int berlin_pwm_suspend(struct device *dev) { @@ -290,7 +274,6 @@ static SIMPLE_DEV_PM_OPS(berlin_pwm_pm_ops, berlin_pwm_suspend, static struct platform_driver berlin_pwm_driver = { .probe = berlin_pwm_probe, - .remove_new = berlin_pwm_remove, .driver = { .name = "berlin-pwm", .of_match_table = berlin_pwm_match, -- GitLab From 721ee188488381f0c2d4e04fbc2200963fda23b7 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 7 Sep 2023 17:12:37 +0100 Subject: [PATCH 0591/1451] pwm: dwc: split pci out of core driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moving towards adding non-pci support for the driver, move the pci parts out of the core into their own module. This is partly due to the module_driver() code only being allowed once in a module and also to avoid a number of #ifdef if we build a single file in a system without pci support. Signed-off-by: Ben Dooks Acked-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230907161242.67190-2-ben.dooks@codethink.co.uk Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/Kconfig | 14 ++- drivers/pwm/Makefile | 1 + drivers/pwm/pwm-dwc-core.c | 175 +++++++++++++++++++++++++++++++++ drivers/pwm/pwm-dwc.c | 196 +------------------------------------ drivers/pwm/pwm-dwc.h | 60 ++++++++++++ 5 files changed, 252 insertions(+), 194 deletions(-) create mode 100644 drivers/pwm/pwm-dwc-core.c create mode 100644 drivers/pwm/pwm-dwc.h diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index ce22b1f311f5a..4b956d661755d 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -186,9 +186,19 @@ config PWM_CROS_EC PWM driver for exposing a PWM attached to the ChromeOS Embedded Controller. +config PWM_DWC_CORE + tristate + depends on HAS_IOMEM + help + PWM driver for Synopsys DWC PWM Controller. + + To compile this driver as a module, build the dependecies as + modules, this will be called pwm-dwc-core. + config PWM_DWC - tristate "DesignWare PWM Controller" - depends on PCI + tristate "DesignWare PWM Controller (PCI bus)" + depends on HAS_IOMEM && PCI + select PWM_DWC_CORE help PWM driver for Synopsys DWC PWM Controller attached to a PCI bus. diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index c822389c2a24c..c5ec9e168ee7c 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_PWM_CLK) += pwm-clk.o obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o obj-$(CONFIG_PWM_CRC) += pwm-crc.o obj-$(CONFIG_PWM_CROS_EC) += pwm-cros-ec.o +obj-$(CONFIG_PWM_DWC_CORE) += pwm-dwc-core.o obj-$(CONFIG_PWM_DWC) += pwm-dwc.o obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o diff --git a/drivers/pwm/pwm-dwc-core.c b/drivers/pwm/pwm-dwc-core.c new file mode 100644 index 0000000000000..34934b71a75da --- /dev/null +++ b/drivers/pwm/pwm-dwc-core.c @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DesignWare PWM Controller driver core + * + * Copyright (C) 2018-2020 Intel Corporation + * + * Author: Felipe Balbi (Intel) + * Author: Jarkko Nikula + * Author: Raymond Tan + */ + +#define DEFAULT_SYMBOL_NAMESPACE dwc_pwm + +#include +#include +#include +#include +#include +#include +#include + +#include "pwm-dwc.h" + +static void __dwc_pwm_set_enable(struct dwc_pwm *dwc, int pwm, int enabled) +{ + u32 reg; + + reg = dwc_pwm_readl(dwc, DWC_TIM_CTRL(pwm)); + + if (enabled) + reg |= DWC_TIM_CTRL_EN; + else + reg &= ~DWC_TIM_CTRL_EN; + + dwc_pwm_writel(dwc, reg, DWC_TIM_CTRL(pwm)); +} + +static int __dwc_pwm_configure_timer(struct dwc_pwm *dwc, + struct pwm_device *pwm, + const struct pwm_state *state) +{ + u64 tmp; + u32 ctrl; + u32 high; + u32 low; + + /* + * Calculate width of low and high period in terms of input clock + * periods and check are the result within HW limits between 1 and + * 2^32 periods. + */ + tmp = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, DWC_CLK_PERIOD_NS); + if (tmp < 1 || tmp > (1ULL << 32)) + return -ERANGE; + low = tmp - 1; + + tmp = DIV_ROUND_CLOSEST_ULL(state->period - state->duty_cycle, + DWC_CLK_PERIOD_NS); + if (tmp < 1 || tmp > (1ULL << 32)) + return -ERANGE; + high = tmp - 1; + + /* + * Specification says timer usage flow is to disable timer, then + * program it followed by enable. It also says Load Count is loaded + * into timer after it is enabled - either after a disable or + * a reset. Based on measurements it happens also without disable + * whenever Load Count is updated. But follow the specification. + */ + __dwc_pwm_set_enable(dwc, pwm->hwpwm, false); + + /* + * Write Load Count and Load Count 2 registers. Former defines the + * width of low period and latter the width of high period in terms + * multiple of input clock periods: + * Width = ((Count + 1) * input clock period). + */ + dwc_pwm_writel(dwc, low, DWC_TIM_LD_CNT(pwm->hwpwm)); + dwc_pwm_writel(dwc, high, DWC_TIM_LD_CNT2(pwm->hwpwm)); + + /* + * Set user-defined mode, timer reloads from Load Count registers + * when it counts down to 0. + * Set PWM mode, it makes output to toggle and width of low and high + * periods are set by Load Count registers. + */ + ctrl = DWC_TIM_CTRL_MODE_USER | DWC_TIM_CTRL_PWM; + dwc_pwm_writel(dwc, ctrl, DWC_TIM_CTRL(pwm->hwpwm)); + + /* + * Enable timer. Output starts from low period. + */ + __dwc_pwm_set_enable(dwc, pwm->hwpwm, state->enabled); + + return 0; +} + +static int dwc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + struct dwc_pwm *dwc = to_dwc_pwm(chip); + + if (state->polarity != PWM_POLARITY_INVERSED) + return -EINVAL; + + if (state->enabled) { + if (!pwm->state.enabled) + pm_runtime_get_sync(chip->dev); + return __dwc_pwm_configure_timer(dwc, pwm, state); + } else { + if (pwm->state.enabled) { + __dwc_pwm_set_enable(dwc, pwm->hwpwm, false); + pm_runtime_put_sync(chip->dev); + } + } + + return 0; +} + +static int dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct dwc_pwm *dwc = to_dwc_pwm(chip); + u64 duty, period; + + pm_runtime_get_sync(chip->dev); + + state->enabled = !!(dwc_pwm_readl(dwc, + DWC_TIM_CTRL(pwm->hwpwm)) & DWC_TIM_CTRL_EN); + + duty = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(pwm->hwpwm)); + duty += 1; + duty *= DWC_CLK_PERIOD_NS; + state->duty_cycle = duty; + + period = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(pwm->hwpwm)); + period += 1; + period *= DWC_CLK_PERIOD_NS; + period += duty; + state->period = period; + + state->polarity = PWM_POLARITY_INVERSED; + + pm_runtime_put_sync(chip->dev); + + return 0; +} + +static const struct pwm_ops dwc_pwm_ops = { + .apply = dwc_pwm_apply, + .get_state = dwc_pwm_get_state, +}; + +struct dwc_pwm *dwc_pwm_alloc(struct device *dev) +{ + struct dwc_pwm *dwc; + + dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL); + if (!dwc) + return NULL; + + dwc->chip.dev = dev; + dwc->chip.ops = &dwc_pwm_ops; + dwc->chip.npwm = DWC_TIMERS_TOTAL; + + dev_set_drvdata(dev, dwc); + return dwc; +} +EXPORT_SYMBOL_GPL(dwc_pwm_alloc); + +MODULE_AUTHOR("Felipe Balbi (Intel)"); +MODULE_AUTHOR("Jarkko Nikula "); +MODULE_AUTHOR("Raymond Tan "); +MODULE_DESCRIPTION("DesignWare PWM Controller"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pwm/pwm-dwc.c b/drivers/pwm/pwm-dwc.c index 53fe00ccd47ef..bd9cadb497d70 100644 --- a/drivers/pwm/pwm-dwc.c +++ b/drivers/pwm/pwm-dwc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * DesignWare PWM Controller driver + * DesignWare PWM Controller driver (PCI part) * * Copyright (C) 2018-2020 Intel Corporation * @@ -13,6 +13,8 @@ * periods are one or more input clock periods long. */ +#define DEFAULT_MOUDLE_NAMESPACE dwc_pwm + #include #include #include @@ -21,197 +23,7 @@ #include #include -#define DWC_TIM_LD_CNT(n) ((n) * 0x14) -#define DWC_TIM_LD_CNT2(n) (((n) * 4) + 0xb0) -#define DWC_TIM_CUR_VAL(n) (((n) * 0x14) + 0x04) -#define DWC_TIM_CTRL(n) (((n) * 0x14) + 0x08) -#define DWC_TIM_EOI(n) (((n) * 0x14) + 0x0c) -#define DWC_TIM_INT_STS(n) (((n) * 0x14) + 0x10) - -#define DWC_TIMERS_INT_STS 0xa0 -#define DWC_TIMERS_EOI 0xa4 -#define DWC_TIMERS_RAW_INT_STS 0xa8 -#define DWC_TIMERS_COMP_VERSION 0xac - -#define DWC_TIMERS_TOTAL 8 -#define DWC_CLK_PERIOD_NS 10 - -/* Timer Control Register */ -#define DWC_TIM_CTRL_EN BIT(0) -#define DWC_TIM_CTRL_MODE BIT(1) -#define DWC_TIM_CTRL_MODE_FREE (0 << 1) -#define DWC_TIM_CTRL_MODE_USER (1 << 1) -#define DWC_TIM_CTRL_INT_MASK BIT(2) -#define DWC_TIM_CTRL_PWM BIT(3) - -struct dwc_pwm_ctx { - u32 cnt; - u32 cnt2; - u32 ctrl; -}; - -struct dwc_pwm { - struct pwm_chip chip; - void __iomem *base; - struct dwc_pwm_ctx ctx[DWC_TIMERS_TOTAL]; -}; -#define to_dwc_pwm(p) (container_of((p), struct dwc_pwm, chip)) - -static inline u32 dwc_pwm_readl(struct dwc_pwm *dwc, u32 offset) -{ - return readl(dwc->base + offset); -} - -static inline void dwc_pwm_writel(struct dwc_pwm *dwc, u32 value, u32 offset) -{ - writel(value, dwc->base + offset); -} - -static void __dwc_pwm_set_enable(struct dwc_pwm *dwc, int pwm, int enabled) -{ - u32 reg; - - reg = dwc_pwm_readl(dwc, DWC_TIM_CTRL(pwm)); - - if (enabled) - reg |= DWC_TIM_CTRL_EN; - else - reg &= ~DWC_TIM_CTRL_EN; - - dwc_pwm_writel(dwc, reg, DWC_TIM_CTRL(pwm)); -} - -static int __dwc_pwm_configure_timer(struct dwc_pwm *dwc, - struct pwm_device *pwm, - const struct pwm_state *state) -{ - u64 tmp; - u32 ctrl; - u32 high; - u32 low; - - /* - * Calculate width of low and high period in terms of input clock - * periods and check are the result within HW limits between 1 and - * 2^32 periods. - */ - tmp = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, DWC_CLK_PERIOD_NS); - if (tmp < 1 || tmp > (1ULL << 32)) - return -ERANGE; - low = tmp - 1; - - tmp = DIV_ROUND_CLOSEST_ULL(state->period - state->duty_cycle, - DWC_CLK_PERIOD_NS); - if (tmp < 1 || tmp > (1ULL << 32)) - return -ERANGE; - high = tmp - 1; - - /* - * Specification says timer usage flow is to disable timer, then - * program it followed by enable. It also says Load Count is loaded - * into timer after it is enabled - either after a disable or - * a reset. Based on measurements it happens also without disable - * whenever Load Count is updated. But follow the specification. - */ - __dwc_pwm_set_enable(dwc, pwm->hwpwm, false); - - /* - * Write Load Count and Load Count 2 registers. Former defines the - * width of low period and latter the width of high period in terms - * multiple of input clock periods: - * Width = ((Count + 1) * input clock period). - */ - dwc_pwm_writel(dwc, low, DWC_TIM_LD_CNT(pwm->hwpwm)); - dwc_pwm_writel(dwc, high, DWC_TIM_LD_CNT2(pwm->hwpwm)); - - /* - * Set user-defined mode, timer reloads from Load Count registers - * when it counts down to 0. - * Set PWM mode, it makes output to toggle and width of low and high - * periods are set by Load Count registers. - */ - ctrl = DWC_TIM_CTRL_MODE_USER | DWC_TIM_CTRL_PWM; - dwc_pwm_writel(dwc, ctrl, DWC_TIM_CTRL(pwm->hwpwm)); - - /* - * Enable timer. Output starts from low period. - */ - __dwc_pwm_set_enable(dwc, pwm->hwpwm, state->enabled); - - return 0; -} - -static int dwc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - const struct pwm_state *state) -{ - struct dwc_pwm *dwc = to_dwc_pwm(chip); - - if (state->polarity != PWM_POLARITY_INVERSED) - return -EINVAL; - - if (state->enabled) { - if (!pwm->state.enabled) - pm_runtime_get_sync(chip->dev); - return __dwc_pwm_configure_timer(dwc, pwm, state); - } else { - if (pwm->state.enabled) { - __dwc_pwm_set_enable(dwc, pwm->hwpwm, false); - pm_runtime_put_sync(chip->dev); - } - } - - return 0; -} - -static int dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) -{ - struct dwc_pwm *dwc = to_dwc_pwm(chip); - u64 duty, period; - - pm_runtime_get_sync(chip->dev); - - state->enabled = !!(dwc_pwm_readl(dwc, - DWC_TIM_CTRL(pwm->hwpwm)) & DWC_TIM_CTRL_EN); - - duty = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(pwm->hwpwm)); - duty += 1; - duty *= DWC_CLK_PERIOD_NS; - state->duty_cycle = duty; - - period = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(pwm->hwpwm)); - period += 1; - period *= DWC_CLK_PERIOD_NS; - period += duty; - state->period = period; - - state->polarity = PWM_POLARITY_INVERSED; - - pm_runtime_put_sync(chip->dev); - - return 0; -} - -static const struct pwm_ops dwc_pwm_ops = { - .apply = dwc_pwm_apply, - .get_state = dwc_pwm_get_state, -}; - -static struct dwc_pwm *dwc_pwm_alloc(struct device *dev) -{ - struct dwc_pwm *dwc; - - dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL); - if (!dwc) - return NULL; - - dwc->chip.dev = dev; - dwc->chip.ops = &dwc_pwm_ops; - dwc->chip.npwm = DWC_TIMERS_TOTAL; - - dev_set_drvdata(dev, dwc); - return dwc; -} +#include "pwm-dwc.h" static int dwc_pwm_probe(struct pci_dev *pci, const struct pci_device_id *id) { diff --git a/drivers/pwm/pwm-dwc.h b/drivers/pwm/pwm-dwc.h new file mode 100644 index 0000000000000..56deab4e28ece --- /dev/null +++ b/drivers/pwm/pwm-dwc.h @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DesignWare PWM Controller driver + * + * Copyright (C) 2018-2020 Intel Corporation + * + * Author: Felipe Balbi (Intel) + * Author: Jarkko Nikula + * Author: Raymond Tan + */ + +MODULE_IMPORT_NS(dwc_pwm); + +#define DWC_TIM_LD_CNT(n) ((n) * 0x14) +#define DWC_TIM_LD_CNT2(n) (((n) * 4) + 0xb0) +#define DWC_TIM_CUR_VAL(n) (((n) * 0x14) + 0x04) +#define DWC_TIM_CTRL(n) (((n) * 0x14) + 0x08) +#define DWC_TIM_EOI(n) (((n) * 0x14) + 0x0c) +#define DWC_TIM_INT_STS(n) (((n) * 0x14) + 0x10) + +#define DWC_TIMERS_INT_STS 0xa0 +#define DWC_TIMERS_EOI 0xa4 +#define DWC_TIMERS_RAW_INT_STS 0xa8 +#define DWC_TIMERS_COMP_VERSION 0xac + +#define DWC_TIMERS_TOTAL 8 +#define DWC_CLK_PERIOD_NS 10 + +/* Timer Control Register */ +#define DWC_TIM_CTRL_EN BIT(0) +#define DWC_TIM_CTRL_MODE BIT(1) +#define DWC_TIM_CTRL_MODE_FREE (0 << 1) +#define DWC_TIM_CTRL_MODE_USER (1 << 1) +#define DWC_TIM_CTRL_INT_MASK BIT(2) +#define DWC_TIM_CTRL_PWM BIT(3) + +struct dwc_pwm_ctx { + u32 cnt; + u32 cnt2; + u32 ctrl; +}; + +struct dwc_pwm { + struct pwm_chip chip; + void __iomem *base; + struct dwc_pwm_ctx ctx[DWC_TIMERS_TOTAL]; +}; +#define to_dwc_pwm(p) (container_of((p), struct dwc_pwm, chip)) + +static inline u32 dwc_pwm_readl(struct dwc_pwm *dwc, u32 offset) +{ + return readl(dwc->base + offset); +} + +static inline void dwc_pwm_writel(struct dwc_pwm *dwc, u32 value, u32 offset) +{ + writel(value, dwc->base + offset); +} + +extern struct dwc_pwm *dwc_pwm_alloc(struct device *dev); -- GitLab From 81432e2e5132e681874f500220c21dc3fdfda42b Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 7 Sep 2023 17:12:38 +0100 Subject: [PATCH 0592/1451] pwm: dwc: make timer clock configurable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a configurable clock base rate for the pwm as when being built for non-PCI the block may be sourced from an internal clock. Signed-off-by: Ben Dooks Reviewed-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230907161242.67190-3-ben.dooks@codethink.co.uk Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-dwc-core.c | 9 +++++---- drivers/pwm/pwm-dwc.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/pwm/pwm-dwc-core.c b/drivers/pwm/pwm-dwc-core.c index 34934b71a75da..8e716470390e1 100644 --- a/drivers/pwm/pwm-dwc-core.c +++ b/drivers/pwm/pwm-dwc-core.c @@ -49,13 +49,13 @@ static int __dwc_pwm_configure_timer(struct dwc_pwm *dwc, * periods and check are the result within HW limits between 1 and * 2^32 periods. */ - tmp = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, DWC_CLK_PERIOD_NS); + tmp = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, dwc->clk_ns); if (tmp < 1 || tmp > (1ULL << 32)) return -ERANGE; low = tmp - 1; tmp = DIV_ROUND_CLOSEST_ULL(state->period - state->duty_cycle, - DWC_CLK_PERIOD_NS); + dwc->clk_ns); if (tmp < 1 || tmp > (1ULL << 32)) return -ERANGE; high = tmp - 1; @@ -130,12 +130,12 @@ static int dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, duty = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(pwm->hwpwm)); duty += 1; - duty *= DWC_CLK_PERIOD_NS; + duty *= dwc->clk_ns; state->duty_cycle = duty; period = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(pwm->hwpwm)); period += 1; - period *= DWC_CLK_PERIOD_NS; + period *= dwc->clk_ns; period += duty; state->period = period; @@ -159,6 +159,7 @@ struct dwc_pwm *dwc_pwm_alloc(struct device *dev) if (!dwc) return NULL; + dwc->clk_ns = 10; dwc->chip.dev = dev; dwc->chip.ops = &dwc_pwm_ops; dwc->chip.npwm = DWC_TIMERS_TOTAL; diff --git a/drivers/pwm/pwm-dwc.h b/drivers/pwm/pwm-dwc.h index 56deab4e28ece..64795247c54ce 100644 --- a/drivers/pwm/pwm-dwc.h +++ b/drivers/pwm/pwm-dwc.h @@ -24,7 +24,6 @@ MODULE_IMPORT_NS(dwc_pwm); #define DWC_TIMERS_COMP_VERSION 0xac #define DWC_TIMERS_TOTAL 8 -#define DWC_CLK_PERIOD_NS 10 /* Timer Control Register */ #define DWC_TIM_CTRL_EN BIT(0) @@ -43,6 +42,7 @@ struct dwc_pwm_ctx { struct dwc_pwm { struct pwm_chip chip; void __iomem *base; + unsigned int clk_ns; struct dwc_pwm_ctx ctx[DWC_TIMERS_TOTAL]; }; #define to_dwc_pwm(p) (container_of((p), struct dwc_pwm, chip)) -- GitLab From 4aff152d14c14f60dba7dad4ed0014d6e7c0cd0a Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 7 Sep 2023 17:12:39 +0100 Subject: [PATCH 0593/1451] pwm: dwc: add PWM bit unset in get_state call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we are not in PWM mode, then the output is technically a 50% output based on a single timer instead of the high-low based on the two counters. Add a check for the PWM mode in dwc_pwm_get_state() and if DWC_TIM_CTRL_PWM is not set, then return a 50% cycle. This may only be an issue on initialisation, as the rest of the code currently assumes we're always going to have the extended PWM mode using two counters. Signed-off-by: Ben Dooks Reviewed-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230907161242.67190-4-ben.dooks@codethink.co.uk Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-dwc-core.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/drivers/pwm/pwm-dwc-core.c b/drivers/pwm/pwm-dwc-core.c index 8e716470390e1..ea63dd741f5cc 100644 --- a/drivers/pwm/pwm-dwc-core.c +++ b/drivers/pwm/pwm-dwc-core.c @@ -122,24 +122,32 @@ static int dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, { struct dwc_pwm *dwc = to_dwc_pwm(chip); u64 duty, period; + u32 ctrl, ld, ld2; pm_runtime_get_sync(chip->dev); - state->enabled = !!(dwc_pwm_readl(dwc, - DWC_TIM_CTRL(pwm->hwpwm)) & DWC_TIM_CTRL_EN); + ctrl = dwc_pwm_readl(dwc, DWC_TIM_CTRL(pwm->hwpwm)); + ld = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(pwm->hwpwm)); + ld2 = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(pwm->hwpwm)); - duty = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(pwm->hwpwm)); - duty += 1; - duty *= dwc->clk_ns; - state->duty_cycle = duty; + state->enabled = !!(ctrl & DWC_TIM_CTRL_EN); - period = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(pwm->hwpwm)); - period += 1; - period *= dwc->clk_ns; - period += duty; - state->period = period; + /* + * If we're not in PWM, technically the output is a 50-50 + * based on the timer load-count only. + */ + if (ctrl & DWC_TIM_CTRL_PWM) { + duty = (ld + 1) * dwc->clk_ns; + period = (ld2 + 1) * dwc->clk_ns; + period += duty; + } else { + duty = (ld + 1) * dwc->clk_ns; + period = duty * 2; + } state->polarity = PWM_POLARITY_INVERSED; + state->period = period; + state->duty_cycle = duty; pm_runtime_put_sync(chip->dev); -- GitLab From 8151b37b418310c83f133a9ea8ec2a654fb30d20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 11 Sep 2023 17:44:54 +0200 Subject: [PATCH 0594/1451] pwm: Adapt sysfs API documentation to reality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most low-level PWM drivers support duty_cycle == period, and so does the sysfs API. Also polarity can be changed for enabled PWMs since commit 39100ceea79f ("pwm: Switch to the atomic API"). Reported-by: Jens Gehrlein Link: https://lore.kernel.org/r/20230911154454.675057-1-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- Documentation/driver-api/pwm.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/driver-api/pwm.rst b/Documentation/driver-api/pwm.rst index 3fdc95f7a1d15..bb264490a87a1 100644 --- a/Documentation/driver-api/pwm.rst +++ b/Documentation/driver-api/pwm.rst @@ -111,13 +111,13 @@ channel that was exported. The following properties will then be available: duty_cycle The active time of the PWM signal (read/write). - Value is in nanoseconds and must be less than the period. + Value is in nanoseconds and must be less than or equal to the period. polarity Changes the polarity of the PWM signal (read/write). Writes to this property only work if the PWM chip supports changing - the polarity. The polarity can only be changed if the PWM is not - enabled. Value is the string "normal" or "inversed". + the polarity. + Value is the string "normal" or "inversed". enable Enable/disable the PWM signal (read/write). -- GitLab From b498c14efd4241d79999b9bb943e963eb982450c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 29 Sep 2023 18:19:08 +0200 Subject: [PATCH 0595/1451] pwm: bcm-iproc: Simplify using devm functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With devm_clk_get_enabled() the call to clk_disable_unprepare() can be dropped from the error path and the remove callback. With devm_pwmchip_add() pwmchip_remove() can be dropped. Then the remove callback is empty and can go away, too. Also use dev_err_probe() for simplified (and improved) error reporting. Link: https://lore.kernel.org/r/20230929161918.2410424-2-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-bcm-iproc.c | 37 +++++++++---------------------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/drivers/pwm/pwm-bcm-iproc.c b/drivers/pwm/pwm-bcm-iproc.c index 1da902440df24..758254025683d 100644 --- a/drivers/pwm/pwm-bcm-iproc.c +++ b/drivers/pwm/pwm-bcm-iproc.c @@ -206,18 +206,10 @@ static int iproc_pwmc_probe(struct platform_device *pdev) if (IS_ERR(ip->base)) return PTR_ERR(ip->base); - ip->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(ip->clk)) { - dev_err(&pdev->dev, "failed to get clock: %ld\n", - PTR_ERR(ip->clk)); - return PTR_ERR(ip->clk); - } - - ret = clk_prepare_enable(ip->clk); - if (ret < 0) { - dev_err(&pdev->dev, "failed to enable clock: %d\n", ret); - return ret; - } + ip->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(ip->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(ip->clk), + "failed to get clock\n"); /* Set full drive and normal polarity for all channels */ value = readl(ip->base + IPROC_PWM_CTRL_OFFSET); @@ -229,22 +221,12 @@ static int iproc_pwmc_probe(struct platform_device *pdev) writel(value, ip->base + IPROC_PWM_CTRL_OFFSET); - ret = pwmchip_add(&ip->chip); - if (ret < 0) { - dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); - clk_disable_unprepare(ip->clk); - } - - return ret; -} - -static void iproc_pwmc_remove(struct platform_device *pdev) -{ - struct iproc_pwmc *ip = platform_get_drvdata(pdev); + ret = devm_pwmchip_add(&pdev->dev, &ip->chip); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "failed to add PWM chip\n"); - pwmchip_remove(&ip->chip); - - clk_disable_unprepare(ip->clk); + return 0; } static const struct of_device_id bcm_iproc_pwmc_dt[] = { @@ -259,7 +241,6 @@ static struct platform_driver iproc_pwmc_driver = { .of_match_table = bcm_iproc_pwmc_dt, }, .probe = iproc_pwmc_probe, - .remove_new = iproc_pwmc_remove, }; module_platform_driver(iproc_pwmc_driver); -- GitLab From 2ce7b7f6704c9a8040fb12eb2b682986d9129e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 29 Sep 2023 18:19:09 +0200 Subject: [PATCH 0596/1451] pwm: bcm2835: Simplify using devm functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With devm_clk_get_enabled() the call to clk_disable_unprepare() can be dropped from the error path and the remove callback. With devm_pwmchip_add() pwmchip_remove() can be dropped. Then the remove callback is empty and can go away, too. With bcm2835_pwm_remove() the only user of platform_get_drvdata() is gone and so platform_set_drvdata() can be dropped from .probe(), too. Also use dev_err_probe() for simplified (and improved) error reporting. Link: https://lore.kernel.org/r/20230929161918.2410424-3-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-bcm2835.c | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c index af318a35d510e..8c69ddfea2d0f 100644 --- a/drivers/pwm/pwm-bcm2835.c +++ b/drivers/pwm/pwm-bcm2835.c @@ -146,39 +146,21 @@ static int bcm2835_pwm_probe(struct platform_device *pdev) if (IS_ERR(pc->base)) return PTR_ERR(pc->base); - pc->clk = devm_clk_get(&pdev->dev, NULL); + pc->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(pc->clk)) return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk), "clock not found\n"); - ret = clk_prepare_enable(pc->clk); - if (ret) - return ret; - pc->chip.dev = &pdev->dev; pc->chip.ops = &bcm2835_pwm_ops; pc->chip.npwm = 2; - platform_set_drvdata(pdev, pc); - - ret = pwmchip_add(&pc->chip); + ret = devm_pwmchip_add(&pdev->dev, &pc->chip); if (ret < 0) - goto add_fail; + return dev_err_probe(&pdev->dev, ret, + "failed to add pwmchip\n"); return 0; - -add_fail: - clk_disable_unprepare(pc->clk); - return ret; -} - -static void bcm2835_pwm_remove(struct platform_device *pdev) -{ - struct bcm2835_pwm *pc = platform_get_drvdata(pdev); - - pwmchip_remove(&pc->chip); - - clk_disable_unprepare(pc->clk); } static const struct of_device_id bcm2835_pwm_of_match[] = { @@ -193,7 +175,6 @@ static struct platform_driver bcm2835_pwm_driver = { .of_match_table = bcm2835_pwm_of_match, }, .probe = bcm2835_pwm_probe, - .remove_new = bcm2835_pwm_remove, }; module_platform_driver(bcm2835_pwm_driver); -- GitLab From 5af615f8ace2b027c582ea62c55b46d71e5287ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 29 Sep 2023 18:19:10 +0200 Subject: [PATCH 0597/1451] pwm: brcmstb: Simplify using devm functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With devm_clk_get_enabled() the call to clk_disable_unprepare() can be dropped from the error path and the remove callback. With devm_pwmchip_add() pwmchip_remove() can be dropped. Then the remove callback is empty and can go away, too. Also use dev_err_probe() for simplified (and improved) error reporting. Link: https://lore.kernel.org/r/20230929161918.2410424-4-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-brcmstb.c | 42 +++++++++------------------------------ 1 file changed, 9 insertions(+), 33 deletions(-) diff --git a/drivers/pwm/pwm-brcmstb.c b/drivers/pwm/pwm-brcmstb.c index 96967f8a8dad9..62bd01c083503 100644 --- a/drivers/pwm/pwm-brcmstb.c +++ b/drivers/pwm/pwm-brcmstb.c @@ -237,17 +237,10 @@ static int brcmstb_pwm_probe(struct platform_device *pdev) if (!p) return -ENOMEM; - p->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(p->clk)) { - dev_err(&pdev->dev, "failed to obtain clock\n"); - return PTR_ERR(p->clk); - } - - ret = clk_prepare_enable(p->clk); - if (ret < 0) { - dev_err(&pdev->dev, "failed to enable clock: %d\n", ret); - return ret; - } + p->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(p->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(p->clk), + "failed to obtain clock\n"); platform_set_drvdata(pdev, p); @@ -256,30 +249,14 @@ static int brcmstb_pwm_probe(struct platform_device *pdev) p->chip.npwm = 2; p->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(p->base)) { - ret = PTR_ERR(p->base); - goto out_clk; - } + if (IS_ERR(p->base)) + return PTR_ERR(p->base); - ret = pwmchip_add(&p->chip); - if (ret) { - dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); - goto out_clk; - } + ret = devm_pwmchip_add(&pdev->dev, &p->chip); + if (ret) + return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n"); return 0; - -out_clk: - clk_disable_unprepare(p->clk); - return ret; -} - -static void brcmstb_pwm_remove(struct platform_device *pdev) -{ - struct brcmstb_pwm *p = platform_get_drvdata(pdev); - - pwmchip_remove(&p->chip); - clk_disable_unprepare(p->clk); } #ifdef CONFIG_PM_SLEEP @@ -307,7 +284,6 @@ static SIMPLE_DEV_PM_OPS(brcmstb_pwm_pm_ops, brcmstb_pwm_suspend, static struct platform_driver brcmstb_pwm_driver = { .probe = brcmstb_pwm_probe, - .remove_new = brcmstb_pwm_remove, .driver = { .name = "pwm-brcmstb", .of_match_table = brcmstb_pwm_of_match, -- GitLab From 92fcd5b682e410cd136d6ad4c26884487a35a7cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 29 Sep 2023 18:19:11 +0200 Subject: [PATCH 0598/1451] pwm: imx-tpm: Simplify using devm functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With devm_clk_get_enabled() the call to clk_disable_unprepare() can be dropped from the error path and the remove callback. With devm_pwmchip_add() pwmchip_remove() can be dropped. Then the remove callback is empty and can go away, too. Also use dev_err_probe() for simplified (and improved) error reporting. Link: https://lore.kernel.org/r/20230929161918.2410424-5-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx-tpm.c | 29 +++++------------------------ 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/drivers/pwm/pwm-imx-tpm.c b/drivers/pwm/pwm-imx-tpm.c index fe8bf598d3889..dc6aafeb9f7b4 100644 --- a/drivers/pwm/pwm-imx-tpm.c +++ b/drivers/pwm/pwm-imx-tpm.c @@ -350,18 +350,11 @@ static int pwm_imx_tpm_probe(struct platform_device *pdev) if (IS_ERR(tpm->base)) return PTR_ERR(tpm->base); - tpm->clk = devm_clk_get(&pdev->dev, NULL); + tpm->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(tpm->clk)) return dev_err_probe(&pdev->dev, PTR_ERR(tpm->clk), "failed to get PWM clock\n"); - ret = clk_prepare_enable(tpm->clk); - if (ret) { - dev_err(&pdev->dev, - "failed to prepare or enable clock: %d\n", ret); - return ret; - } - tpm->chip.dev = &pdev->dev; tpm->chip.ops = &imx_tpm_pwm_ops; @@ -371,22 +364,11 @@ static int pwm_imx_tpm_probe(struct platform_device *pdev) mutex_init(&tpm->lock); - ret = pwmchip_add(&tpm->chip); - if (ret) { - dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); - clk_disable_unprepare(tpm->clk); - } - - return ret; -} - -static void pwm_imx_tpm_remove(struct platform_device *pdev) -{ - struct imx_tpm_pwm_chip *tpm = platform_get_drvdata(pdev); - - pwmchip_remove(&tpm->chip); + ret = devm_pwmchip_add(&pdev->dev, &tpm->chip); + if (ret) + return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n"); - clk_disable_unprepare(tpm->clk); + return 0; } static int __maybe_unused pwm_imx_tpm_suspend(struct device *dev) @@ -436,7 +418,6 @@ static struct platform_driver imx_tpm_pwm_driver = { .pm = &imx_tpm_pwm_pm, }, .probe = pwm_imx_tpm_probe, - .remove_new = pwm_imx_tpm_remove, }; module_platform_driver(imx_tpm_pwm_driver); -- GitLab From 05c9b6f8e53446c6f7e9ff52e181b4f30459f452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 29 Sep 2023 18:19:12 +0200 Subject: [PATCH 0599/1451] pwm: mtk-disp: Simplify using devm_pwmchip_add() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With devm_pwmchip_add() pwmchip_remove() can be dropped from the remove callback. Then the remove callback is empty and can go away, too. With mtk_disp_pwm_remove() the last user of platform_get_drvdata() is gone and so platform_set_drvdata() can be dropped, too. Also use dev_err_probe() for simplified (and improved) error reporting. Link: https://lore.kernel.org/r/20230929161918.2410424-6-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-mtk-disp.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c index 7748e3eaa8186..a72f7be369964 100644 --- a/drivers/pwm/pwm-mtk-disp.c +++ b/drivers/pwm/pwm-mtk-disp.c @@ -246,34 +246,25 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev) mdp->clk_main = devm_clk_get(&pdev->dev, "main"); if (IS_ERR(mdp->clk_main)) - return PTR_ERR(mdp->clk_main); + return dev_err_probe(&pdev->dev, PTR_ERR(mdp->clk_main), + "Failed to get main clock\n"); mdp->clk_mm = devm_clk_get(&pdev->dev, "mm"); if (IS_ERR(mdp->clk_mm)) - return PTR_ERR(mdp->clk_mm); + return dev_err_probe(&pdev->dev, PTR_ERR(mdp->clk_mm), + "Failed to get mm clock\n"); mdp->chip.dev = &pdev->dev; mdp->chip.ops = &mtk_disp_pwm_ops; mdp->chip.npwm = 1; - ret = pwmchip_add(&mdp->chip); - if (ret < 0) { - dev_err(&pdev->dev, "pwmchip_add() failed: %pe\n", ERR_PTR(ret)); - return ret; - } - - platform_set_drvdata(pdev, mdp); + ret = devm_pwmchip_add(&pdev->dev, &mdp->chip); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "pwmchip_add() failed\n"); return 0; } -static void mtk_disp_pwm_remove(struct platform_device *pdev) -{ - struct mtk_disp_pwm *mdp = platform_get_drvdata(pdev); - - pwmchip_remove(&mdp->chip); -} - static const struct mtk_pwm_data mt2701_pwm_data = { .enable_mask = BIT(16), .con0 = 0xa8, @@ -319,7 +310,6 @@ static struct platform_driver mtk_disp_pwm_driver = { .of_match_table = mtk_disp_pwm_of_match, }, .probe = mtk_disp_pwm_probe, - .remove_new = mtk_disp_pwm_remove, }; module_platform_driver(mtk_disp_pwm_driver); -- GitLab From 4f9ab6902b8e74452426686a453e01787846d028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 29 Sep 2023 18:19:13 +0200 Subject: [PATCH 0600/1451] pwm: spear: Simplify using devm functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With devm_clk_get_prepared() the call to clk_unprepare() can be dropped from the error path and the remove callback. With devm_pwmchip_add() pwmchip_remove() can be dropped. Then the remove callback is empty and can go away, too. With spear_pwm_remove() the last user of platform_get_drvdata() is gone and so platform_set_drvdata() can be dropped, too. Also use dev_err_probe() for simplified (and improved) error reporting. Link: https://lore.kernel.org/r/20230929161918.2410424-7-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-spear.c | 40 +++++++++++----------------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/drivers/pwm/pwm-spear.c b/drivers/pwm/pwm-spear.c index 2cbc34cf6799b..ff991319feef8 100644 --- a/drivers/pwm/pwm-spear.c +++ b/drivers/pwm/pwm-spear.c @@ -206,26 +206,21 @@ static int spear_pwm_probe(struct platform_device *pdev) if (IS_ERR(pc->mmio_base)) return PTR_ERR(pc->mmio_base); - pc->clk = devm_clk_get(&pdev->dev, NULL); + pc->clk = devm_clk_get_prepared(&pdev->dev, NULL); if (IS_ERR(pc->clk)) - return PTR_ERR(pc->clk); - - platform_set_drvdata(pdev, pc); + return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk), + "Failed to get clock\n"); pc->chip.dev = &pdev->dev; pc->chip.ops = &spear_pwm_ops; pc->chip.npwm = NUM_PWM; - ret = clk_prepare(pc->clk); - if (ret) - return ret; - if (of_device_is_compatible(np, "st,spear1340-pwm")) { ret = clk_enable(pc->clk); - if (ret) { - clk_unprepare(pc->clk); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to enable clk\n"); + /* * Following enables PWM chip, channels would still be * enabled individually through their control register @@ -237,23 +232,11 @@ static int spear_pwm_probe(struct platform_device *pdev) clk_disable(pc->clk); } - ret = pwmchip_add(&pc->chip); - if (ret < 0) { - clk_unprepare(pc->clk); - dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); - } + ret = devm_pwmchip_add(&pdev->dev, &pc->chip); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "pwmchip_add() failed\n"); - return ret; -} - -static void spear_pwm_remove(struct platform_device *pdev) -{ - struct spear_pwm_chip *pc = platform_get_drvdata(pdev); - - pwmchip_remove(&pc->chip); - - /* clk was prepared in probe, hence unprepare it here */ - clk_unprepare(pc->clk); + return 0; } static const struct of_device_id spear_pwm_of_match[] = { @@ -270,7 +253,6 @@ static struct platform_driver spear_pwm_driver = { .of_match_table = spear_pwm_of_match, }, .probe = spear_pwm_probe, - .remove_new = spear_pwm_remove, }; module_platform_driver(spear_pwm_driver); -- GitLab From d8a2f6f26a079f3d0a34b6146e332797218cb5de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 29 Sep 2023 18:19:14 +0200 Subject: [PATCH 0601/1451] pwm: sprd: Provide a helper to cast a chip to driver data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to most other PWM drivers provide a static inline function to calculate driver data from a given pwmchip. Link: https://lore.kernel.org/r/20230929161918.2410424-8-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-sprd.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c index dfda2152a7c18..98a36ff7df7bb 100644 --- a/drivers/pwm/pwm-sprd.c +++ b/drivers/pwm/pwm-sprd.c @@ -40,6 +40,11 @@ struct sprd_pwm_chip { struct sprd_pwm_chn chn[SPRD_PWM_CHN_NUM]; }; +static inline struct sprd_pwm_chip* sprd_pwm_from_chip(struct pwm_chip *chip) +{ + return container_of(chip, struct sprd_pwm_chip, chip); +} + /* * The list of clocks required by PWM channels, and each channel has 2 clocks: * enable clock and pwm clock. @@ -69,8 +74,7 @@ static void sprd_pwm_write(struct sprd_pwm_chip *spc, u32 hwid, static int sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_state *state) { - struct sprd_pwm_chip *spc = - container_of(chip, struct sprd_pwm_chip, chip); + struct sprd_pwm_chip *spc = sprd_pwm_from_chip(chip); struct sprd_pwm_chn *chn = &spc->chn[pwm->hwpwm]; u32 val, duty, prescale; u64 tmp; @@ -162,8 +166,7 @@ static int sprd_pwm_config(struct sprd_pwm_chip *spc, struct pwm_device *pwm, static int sprd_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state) { - struct sprd_pwm_chip *spc = - container_of(chip, struct sprd_pwm_chip, chip); + struct sprd_pwm_chip *spc = sprd_pwm_from_chip(chip); struct sprd_pwm_chn *chn = &spc->chn[pwm->hwpwm]; struct pwm_state *cstate = &pwm->state; int ret; -- GitLab From 21c0e1aaf7ef0ac3c67e4e1ab68c080adb2a186b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 29 Sep 2023 18:19:15 +0200 Subject: [PATCH 0602/1451] pwm: sprd: Simplify using devm_pwmchip_add() and dev_err_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using devm_pwmchip_add() allows to drop pwmchip_remove() from the remove function which makes this function empty. Then there is no user of drvdata left and platform_set_drvdata() can be dropped, too. Further simplify and improve error returning using dev_err_probe(). Link: https://lore.kernel.org/r/20230929161918.2410424-9-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-sprd.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c index 98a36ff7df7bb..77939e1610067 100644 --- a/drivers/pwm/pwm-sprd.c +++ b/drivers/pwm/pwm-sprd.c @@ -242,10 +242,8 @@ static int sprd_pwm_clk_init(struct sprd_pwm_chip *spc) chn->clk_rate = clk_get_rate(clk_pwm); } - if (!i) { - dev_err(spc->dev, "no available PWM channels\n"); - return -ENODEV; - } + if (!i) + return dev_err_probe(spc->dev, -ENODEV, "no available PWM channels\n"); spc->num_pwms = i; @@ -266,7 +264,6 @@ static int sprd_pwm_probe(struct platform_device *pdev) return PTR_ERR(spc->base); spc->dev = &pdev->dev; - platform_set_drvdata(pdev, spc); ret = sprd_pwm_clk_init(spc); if (ret) @@ -276,20 +273,13 @@ static int sprd_pwm_probe(struct platform_device *pdev) spc->chip.ops = &sprd_pwm_ops; spc->chip.npwm = spc->num_pwms; - ret = pwmchip_add(&spc->chip); + ret = devm_pwmchip_add(&pdev->dev, &spc->chip); if (ret) dev_err(&pdev->dev, "failed to add PWM chip\n"); return ret; } -static void sprd_pwm_remove(struct platform_device *pdev) -{ - struct sprd_pwm_chip *spc = platform_get_drvdata(pdev); - - pwmchip_remove(&spc->chip); -} - static const struct of_device_id sprd_pwm_of_match[] = { { .compatible = "sprd,ums512-pwm", }, { }, @@ -302,7 +292,6 @@ static struct platform_driver sprd_pwm_driver = { .of_match_table = sprd_pwm_of_match, }, .probe = sprd_pwm_probe, - .remove_new = sprd_pwm_remove, }; module_platform_driver(sprd_pwm_driver); -- GitLab From dfbf937916308641e925a23aa12dd7c38ceddd99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 29 Sep 2023 18:19:16 +0200 Subject: [PATCH 0603/1451] pwm: vt8500: Simplify using devm functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With devm_clk_get_prepared() the call to clk_unprepare() can be dropped from the error path and the remove callback. With devm_pwmchip_add() pwmchip_remove() can be dropped. Then the remove callback is empty and can go away, too. With vt8500_pwm_remove() the last user of platform_get_drvdata() is gone and so platform_set_drvdata() can be dropped, too. Also use dev_err_probe() for simplified (and improved) error reporting. Link: https://lore.kernel.org/r/20230929161918.2410424-10-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-vt8500.c | 42 +++++++++------------------------------- 1 file changed, 9 insertions(+), 33 deletions(-) diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c index a96c7f5d90999..5568d5312d3ca 100644 --- a/drivers/pwm/pwm-vt8500.c +++ b/drivers/pwm/pwm-vt8500.c @@ -235,10 +235,8 @@ static int vt8500_pwm_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; int ret; - if (!np) { - dev_err(&pdev->dev, "invalid devicetree node\n"); - return -EINVAL; - } + if (!np) + return dev_err_probe(&pdev->dev, -EINVAL, "invalid devicetree node\n"); vt8500 = devm_kzalloc(&pdev->dev, sizeof(*vt8500), GFP_KERNEL); if (vt8500 == NULL) @@ -248,45 +246,23 @@ static int vt8500_pwm_probe(struct platform_device *pdev) vt8500->chip.ops = &vt8500_pwm_ops; vt8500->chip.npwm = VT8500_NR_PWMS; - vt8500->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(vt8500->clk)) { - dev_err(&pdev->dev, "clock source not specified\n"); - return PTR_ERR(vt8500->clk); - } + vt8500->clk = devm_clk_get_prepared(&pdev->dev, NULL); + if (IS_ERR(vt8500->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(vt8500->clk), "clock source not specified\n"); vt8500->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(vt8500->base)) return PTR_ERR(vt8500->base); - ret = clk_prepare(vt8500->clk); - if (ret < 0) { - dev_err(&pdev->dev, "failed to prepare clock\n"); - return ret; - } - - ret = pwmchip_add(&vt8500->chip); - if (ret < 0) { - dev_err(&pdev->dev, "failed to add PWM chip\n"); - clk_unprepare(vt8500->clk); - return ret; - } - - platform_set_drvdata(pdev, vt8500); - return ret; -} - -static void vt8500_pwm_remove(struct platform_device *pdev) -{ - struct vt8500_chip *vt8500 = platform_get_drvdata(pdev); - - pwmchip_remove(&vt8500->chip); + ret = devm_pwmchip_add(&pdev->dev, &vt8500->chip); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n"); - clk_unprepare(vt8500->clk); + return 0; } static struct platform_driver vt8500_pwm_driver = { .probe = vt8500_pwm_probe, - .remove_new = vt8500_pwm_remove, .driver = { .name = "vt8500-pwm", .of_match_table = vt8500_pwm_dt_ids, -- GitLab From 9608405bdaa5876041d2a1dd388009f89643a2ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 29 Sep 2023 18:19:17 +0200 Subject: [PATCH 0604/1451] pwm: samsung: Consistently use the same name for driver data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver uses mostly "chip" to name samsung_pwm_chip pointers: $ git grep -Pho 'samsung_pwm_chip \*[a-zA-Z0-9_]+(*nla:[a-zA-Z0-9_(])' v6.5-rc1 -- drivers/pwm/pwm-samsung.c | sort | uniq -c 10 samsung_pwm_chip *chip 6 samsung_pwm_chip *our_chip 1 samsung_pwm_chip *pwm However "chip" is supposed to be used for struct pwm_chip pointers and "pwm" for struct pwm_device pointers. So consistently use "our_chip". Link: https://lore.kernel.org/r/20230929161918.2410424-11-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-samsung.c | 130 +++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c index c437fab7ded88..10fe2c13cd804 100644 --- a/drivers/pwm/pwm-samsung.c +++ b/drivers/pwm/pwm-samsung.c @@ -118,21 +118,21 @@ static inline unsigned int to_tcon_channel(unsigned int channel) return (channel == 0) ? 0 : (channel + 1); } -static void __pwm_samsung_manual_update(struct samsung_pwm_chip *chip, +static void __pwm_samsung_manual_update(struct samsung_pwm_chip *our_chip, struct pwm_device *pwm) { unsigned int tcon_chan = to_tcon_channel(pwm->hwpwm); u32 tcon; - tcon = readl(chip->base + REG_TCON); + tcon = readl(our_chip->base + REG_TCON); tcon |= TCON_MANUALUPDATE(tcon_chan); - writel(tcon, chip->base + REG_TCON); + writel(tcon, our_chip->base + REG_TCON); tcon &= ~TCON_MANUALUPDATE(tcon_chan); - writel(tcon, chip->base + REG_TCON); + writel(tcon, our_chip->base + REG_TCON); } -static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm, +static void pwm_samsung_set_divisor(struct samsung_pwm_chip *our_chip, unsigned int channel, u8 divisor) { u8 shift = TCFG1_SHIFT(channel); @@ -140,39 +140,39 @@ static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm, u32 reg; u8 bits; - bits = (fls(divisor) - 1) - pwm->variant.div_base; + bits = (fls(divisor) - 1) - our_chip->variant.div_base; spin_lock_irqsave(&samsung_pwm_lock, flags); - reg = readl(pwm->base + REG_TCFG1); + reg = readl(our_chip->base + REG_TCFG1); reg &= ~(TCFG1_MUX_MASK << shift); reg |= bits << shift; - writel(reg, pwm->base + REG_TCFG1); + writel(reg, our_chip->base + REG_TCFG1); spin_unlock_irqrestore(&samsung_pwm_lock, flags); } -static int pwm_samsung_is_tdiv(struct samsung_pwm_chip *chip, unsigned int chan) +static int pwm_samsung_is_tdiv(struct samsung_pwm_chip *our_chip, unsigned int chan) { - struct samsung_pwm_variant *variant = &chip->variant; + struct samsung_pwm_variant *variant = &our_chip->variant; u32 reg; - reg = readl(chip->base + REG_TCFG1); + reg = readl(our_chip->base + REG_TCFG1); reg >>= TCFG1_SHIFT(chan); reg &= TCFG1_MUX_MASK; return (BIT(reg) & variant->tclk_mask) == 0; } -static unsigned long pwm_samsung_get_tin_rate(struct samsung_pwm_chip *chip, +static unsigned long pwm_samsung_get_tin_rate(struct samsung_pwm_chip *our_chip, unsigned int chan) { unsigned long rate; u32 reg; - rate = clk_get_rate(chip->base_clk); + rate = clk_get_rate(our_chip->base_clk); - reg = readl(chip->base + REG_TCFG0); + reg = readl(our_chip->base + REG_TCFG0); if (chan >= 2) reg >>= TCFG0_PRESCALER1_SHIFT; reg &= TCFG0_PRESCALER_MASK; @@ -180,28 +180,28 @@ static unsigned long pwm_samsung_get_tin_rate(struct samsung_pwm_chip *chip, return rate / (reg + 1); } -static unsigned long pwm_samsung_calc_tin(struct samsung_pwm_chip *chip, +static unsigned long pwm_samsung_calc_tin(struct samsung_pwm_chip *our_chip, unsigned int chan, unsigned long freq) { - struct samsung_pwm_variant *variant = &chip->variant; + struct samsung_pwm_variant *variant = &our_chip->variant; unsigned long rate; struct clk *clk; u8 div; - if (!pwm_samsung_is_tdiv(chip, chan)) { - clk = (chan < 2) ? chip->tclk0 : chip->tclk1; + if (!pwm_samsung_is_tdiv(our_chip, chan)) { + clk = (chan < 2) ? our_chip->tclk0 : our_chip->tclk1; if (!IS_ERR(clk)) { rate = clk_get_rate(clk); if (rate) return rate; } - dev_warn(chip->chip.dev, + dev_warn(our_chip->chip.dev, "tclk of PWM %d is inoperational, using tdiv\n", chan); } - rate = pwm_samsung_get_tin_rate(chip, chan); - dev_dbg(chip->chip.dev, "tin parent at %lu\n", rate); + rate = pwm_samsung_get_tin_rate(our_chip, chan); + dev_dbg(our_chip->chip.dev, "tin parent at %lu\n", rate); /* * Compare minimum PWM frequency that can be achieved with possible @@ -221,7 +221,7 @@ static unsigned long pwm_samsung_calc_tin(struct samsung_pwm_chip *chip, div = variant->div_base; } - pwm_samsung_set_divisor(chip, chan, BIT(div)); + pwm_samsung_set_divisor(our_chip, chan, BIT(div)); return rate >> div; } @@ -293,14 +293,14 @@ static void pwm_samsung_disable(struct pwm_chip *chip, struct pwm_device *pwm) spin_unlock_irqrestore(&samsung_pwm_lock, flags); } -static void pwm_samsung_manual_update(struct samsung_pwm_chip *chip, +static void pwm_samsung_manual_update(struct samsung_pwm_chip *our_chip, struct pwm_device *pwm) { unsigned long flags; spin_lock_irqsave(&samsung_pwm_lock, flags); - __pwm_samsung_manual_update(chip, pwm); + __pwm_samsung_manual_update(our_chip, pwm); spin_unlock_irqrestore(&samsung_pwm_lock, flags); } @@ -384,7 +384,7 @@ static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm, return __pwm_samsung_config(chip, pwm, duty_ns, period_ns, false); } -static void pwm_samsung_set_invert(struct samsung_pwm_chip *chip, +static void pwm_samsung_set_invert(struct samsung_pwm_chip *our_chip, unsigned int channel, bool invert) { unsigned int tcon_chan = to_tcon_channel(channel); @@ -393,17 +393,17 @@ static void pwm_samsung_set_invert(struct samsung_pwm_chip *chip, spin_lock_irqsave(&samsung_pwm_lock, flags); - tcon = readl(chip->base + REG_TCON); + tcon = readl(our_chip->base + REG_TCON); if (invert) { - chip->inverter_mask |= BIT(channel); + our_chip->inverter_mask |= BIT(channel); tcon |= TCON_INVERT(tcon_chan); } else { - chip->inverter_mask &= ~BIT(channel); + our_chip->inverter_mask &= ~BIT(channel); tcon &= ~TCON_INVERT(tcon_chan); } - writel(tcon, chip->base + REG_TCON); + writel(tcon, our_chip->base + REG_TCON); spin_unlock_irqrestore(&samsung_pwm_lock, flags); } @@ -506,9 +506,9 @@ static const struct of_device_id samsung_pwm_matches[] = { }; MODULE_DEVICE_TABLE(of, samsung_pwm_matches); -static int pwm_samsung_parse_dt(struct samsung_pwm_chip *chip) +static int pwm_samsung_parse_dt(struct samsung_pwm_chip *our_chip) { - struct device_node *np = chip->chip.dev->of_node; + struct device_node *np = our_chip->chip.dev->of_node; const struct of_device_id *match; struct property *prop; const __be32 *cur; @@ -518,22 +518,22 @@ static int pwm_samsung_parse_dt(struct samsung_pwm_chip *chip) if (!match) return -ENODEV; - memcpy(&chip->variant, match->data, sizeof(chip->variant)); + memcpy(&our_chip->variant, match->data, sizeof(our_chip->variant)); of_property_for_each_u32(np, "samsung,pwm-outputs", prop, cur, val) { if (val >= SAMSUNG_PWM_NUM) { - dev_err(chip->chip.dev, + dev_err(our_chip->chip.dev, "%s: invalid channel index in samsung,pwm-outputs property\n", __func__); continue; } - chip->variant.output_mask |= BIT(val); + our_chip->variant.output_mask |= BIT(val); } return 0; } #else -static int pwm_samsung_parse_dt(struct samsung_pwm_chip *chip) +static int pwm_samsung_parse_dt(struct samsung_pwm_chip *our_chip) { return -ENODEV; } @@ -542,21 +542,21 @@ static int pwm_samsung_parse_dt(struct samsung_pwm_chip *chip) static int pwm_samsung_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct samsung_pwm_chip *chip; + struct samsung_pwm_chip *our_chip; unsigned int chan; int ret; - chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); - if (chip == NULL) + our_chip = devm_kzalloc(&pdev->dev, sizeof(*our_chip), GFP_KERNEL); + if (our_chip == NULL) return -ENOMEM; - chip->chip.dev = &pdev->dev; - chip->chip.ops = &pwm_samsung_ops; - chip->chip.npwm = SAMSUNG_PWM_NUM; - chip->inverter_mask = BIT(SAMSUNG_PWM_NUM) - 1; + our_chip->chip.dev = &pdev->dev; + our_chip->chip.ops = &pwm_samsung_ops; + our_chip->chip.npwm = SAMSUNG_PWM_NUM; + our_chip->inverter_mask = BIT(SAMSUNG_PWM_NUM) - 1; if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { - ret = pwm_samsung_parse_dt(chip); + ret = pwm_samsung_parse_dt(our_chip); if (ret) return ret; } else { @@ -565,58 +565,58 @@ static int pwm_samsung_probe(struct platform_device *pdev) return -EINVAL; } - memcpy(&chip->variant, pdev->dev.platform_data, - sizeof(chip->variant)); + memcpy(&our_chip->variant, pdev->dev.platform_data, + sizeof(our_chip->variant)); } - chip->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(chip->base)) - return PTR_ERR(chip->base); + our_chip->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(our_chip->base)) + return PTR_ERR(our_chip->base); - chip->base_clk = devm_clk_get(&pdev->dev, "timers"); - if (IS_ERR(chip->base_clk)) { + our_chip->base_clk = devm_clk_get(&pdev->dev, "timers"); + if (IS_ERR(our_chip->base_clk)) { dev_err(dev, "failed to get timer base clk\n"); - return PTR_ERR(chip->base_clk); + return PTR_ERR(our_chip->base_clk); } - ret = clk_prepare_enable(chip->base_clk); + ret = clk_prepare_enable(our_chip->base_clk); if (ret < 0) { dev_err(dev, "failed to enable base clock\n"); return ret; } for (chan = 0; chan < SAMSUNG_PWM_NUM; ++chan) - if (chip->variant.output_mask & BIT(chan)) - pwm_samsung_set_invert(chip, chan, true); + if (our_chip->variant.output_mask & BIT(chan)) + pwm_samsung_set_invert(our_chip, chan, true); /* Following clocks are optional. */ - chip->tclk0 = devm_clk_get(&pdev->dev, "pwm-tclk0"); - chip->tclk1 = devm_clk_get(&pdev->dev, "pwm-tclk1"); + our_chip->tclk0 = devm_clk_get(&pdev->dev, "pwm-tclk0"); + our_chip->tclk1 = devm_clk_get(&pdev->dev, "pwm-tclk1"); - platform_set_drvdata(pdev, chip); + platform_set_drvdata(pdev, our_chip); - ret = pwmchip_add(&chip->chip); + ret = pwmchip_add(&our_chip->chip); if (ret < 0) { dev_err(dev, "failed to register PWM chip\n"); - clk_disable_unprepare(chip->base_clk); + clk_disable_unprepare(our_chip->base_clk); return ret; } dev_dbg(dev, "base_clk at %lu, tclk0 at %lu, tclk1 at %lu\n", - clk_get_rate(chip->base_clk), - !IS_ERR(chip->tclk0) ? clk_get_rate(chip->tclk0) : 0, - !IS_ERR(chip->tclk1) ? clk_get_rate(chip->tclk1) : 0); + clk_get_rate(our_chip->base_clk), + !IS_ERR(our_chip->tclk0) ? clk_get_rate(our_chip->tclk0) : 0, + !IS_ERR(our_chip->tclk1) ? clk_get_rate(our_chip->tclk1) : 0); return 0; } static void pwm_samsung_remove(struct platform_device *pdev) { - struct samsung_pwm_chip *chip = platform_get_drvdata(pdev); + struct samsung_pwm_chip *our_chip = platform_get_drvdata(pdev); - pwmchip_remove(&chip->chip); + pwmchip_remove(&our_chip->chip); - clk_disable_unprepare(chip->base_clk); + clk_disable_unprepare(our_chip->base_clk); } #ifdef CONFIG_PM_SLEEP -- GitLab From 896c450960f5b11f81eaa5822db0801b03be3e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 29 Sep 2023 18:19:18 +0200 Subject: [PATCH 0605/1451] pwm: cros-ec: Simplify using devm_pwmchip_add() and dev_err_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using devm_pwmchip_add() allows to drop pwmchip_remove() from the remove function which makes this function empty. Then there is no user of drvdata left and platform_set_drvdata() can be dropped, too. Further simplify and improve error returning using dev_err_probe(). Link: https://lore.kernel.org/r/20230929161918.2410424-12-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-cros-ec.c | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c index 5ab84e0cb9111..4fbd23e4ef693 100644 --- a/drivers/pwm/pwm-cros-ec.c +++ b/drivers/pwm/pwm-cros-ec.c @@ -265,10 +265,8 @@ static int cros_ec_pwm_probe(struct platform_device *pdev) struct pwm_chip *chip; int ret; - if (!ec) { - dev_err(dev, "no parent EC device\n"); - return -EINVAL; - } + if (!ec) + return dev_err_probe(dev, -EINVAL, "no parent EC device\n"); ec_pwm = devm_kzalloc(dev, sizeof(*ec_pwm), GFP_KERNEL); if (!ec_pwm) @@ -289,10 +287,8 @@ static int cros_ec_pwm_probe(struct platform_device *pdev) chip->npwm = CROS_EC_PWM_DT_COUNT; } else { ret = cros_ec_num_pwms(ec_pwm); - if (ret < 0) { - dev_err(dev, "Couldn't find PWMs: %d\n", ret); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Couldn't find PWMs\n"); chip->npwm = ret; } @@ -303,23 +299,11 @@ static int cros_ec_pwm_probe(struct platform_device *pdev) dev_dbg(dev, "Probed %u PWMs\n", chip->npwm); - ret = pwmchip_add(chip); - if (ret < 0) { - dev_err(dev, "cannot register PWM: %d\n", ret); - return ret; - } - - platform_set_drvdata(pdev, ec_pwm); - - return ret; -} - -static void cros_ec_pwm_remove(struct platform_device *dev) -{ - struct cros_ec_pwm_device *ec_pwm = platform_get_drvdata(dev); - struct pwm_chip *chip = &ec_pwm->chip; + ret = devm_pwmchip_add(dev, chip); + if (ret < 0) + return dev_err_probe(dev, ret, "cannot register PWM\n"); - pwmchip_remove(chip); + return 0; } #ifdef CONFIG_OF @@ -333,7 +317,6 @@ MODULE_DEVICE_TABLE(of, cros_ec_pwm_of_match); static struct platform_driver cros_ec_pwm_driver = { .probe = cros_ec_pwm_probe, - .remove_new = cros_ec_pwm_remove, .driver = { .name = "cros-ec-pwm", .of_match_table = of_match_ptr(cros_ec_pwm_of_match), -- GitLab From 87e51b76c9db8c29cde573af0faf5a3e13e23960 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 9 Oct 2023 12:29:17 -0500 Subject: [PATCH 0606/1451] pwm: pxa: Explicitly include correct DT includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-pxa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index faf6b35b93365..76685f926c758 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include -- GitLab From e9bc4411548aaa738905d37851a0146c16b3bb21 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 4 Oct 2023 10:54:14 -0700 Subject: [PATCH 0607/1451] pwm: brcmstb: Utilize appropriate clock APIs in suspend/resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The suspend/resume functions currently utilize clk_disable()/clk_enable() respectively which may be no-ops with certain clock providers such as SCMI. Fix this to use clk_disable_unprepare() and clk_prepare_enable() respectively as we should. Fixes: 3a9f5957020f ("pwm: Add Broadcom BCM7038 PWM controller support") Signed-off-by: Florian Fainelli Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-brcmstb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-brcmstb.c b/drivers/pwm/pwm-brcmstb.c index 62bd01c083503..73fdd720f4622 100644 --- a/drivers/pwm/pwm-brcmstb.c +++ b/drivers/pwm/pwm-brcmstb.c @@ -264,7 +264,7 @@ static int brcmstb_pwm_suspend(struct device *dev) { struct brcmstb_pwm *p = dev_get_drvdata(dev); - clk_disable(p->clk); + clk_disable_unprepare(p->clk); return 0; } @@ -273,7 +273,7 @@ static int brcmstb_pwm_resume(struct device *dev) { struct brcmstb_pwm *p = dev_get_drvdata(dev); - clk_enable(p->clk); + clk_prepare_enable(p->clk); return 0; } -- GitLab From aacbd65436690244648333cf492f557d162e9f09 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Oct 2023 09:47:27 -0700 Subject: [PATCH 0608/1451] pwm: brcmstb: Checked clk_prepare_enable() return value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check the clk_prepare_enable() return value and propagate it. Suggested-by: Uwe Kleine-König Signed-off-by: Florian Fainelli Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-brcmstb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-brcmstb.c b/drivers/pwm/pwm-brcmstb.c index 73fdd720f4622..b723c2d4f485c 100644 --- a/drivers/pwm/pwm-brcmstb.c +++ b/drivers/pwm/pwm-brcmstb.c @@ -273,9 +273,7 @@ static int brcmstb_pwm_resume(struct device *dev) { struct brcmstb_pwm *p = dev_get_drvdata(dev); - clk_prepare_enable(p->clk); - - return 0; + return clk_prepare_enable(p->clk); } #endif -- GitLab From 119a508c4dc956c859854f40a504c577598b68a8 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 11 Oct 2023 10:07:17 -0700 Subject: [PATCH 0609/1451] pwm: bcm2835: Add support for suspend/resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to other drivers, we need to make sure that the clock is disabled during suspend and re-enabled during resume. Reported-by: Angus Clark Signed-off-by: Florian Fainelli Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-bcm2835.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c index 8c69ddfea2d0f..9777babd5b95c 100644 --- a/drivers/pwm/pwm-bcm2835.c +++ b/drivers/pwm/pwm-bcm2835.c @@ -163,6 +163,25 @@ static int bcm2835_pwm_probe(struct platform_device *pdev) return 0; } +static int bcm2835_pwm_suspend(struct device *dev) +{ + struct bcm2835_pwm *pc = dev_get_drvdata(dev); + + clk_disable_unprepare(pc->clk); + + return 0; +} + +static int bcm2835_pwm_resume(struct device *dev) +{ + struct bcm2835_pwm *pc = dev_get_drvdata(dev); + + return clk_prepare_enable(pc->clk); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(bcm2835_pwm_pm_ops, bcm2835_pwm_suspend, + bcm2835_pwm_resume); + static const struct of_device_id bcm2835_pwm_of_match[] = { { .compatible = "brcm,bcm2835-pwm", }, { /* sentinel */ } @@ -173,6 +192,7 @@ static struct platform_driver bcm2835_pwm_driver = { .driver = { .name = "bcm2835-pwm", .of_match_table = bcm2835_pwm_of_match, + .pm = pm_ptr(&bcm2835_pwm_pm_ops), }, .probe = bcm2835_pwm_probe, }; -- GitLab From f31b2cb85f0ee165d78e1c43f6d69f82cc3b2145 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 6 Oct 2023 12:08:45 +0200 Subject: [PATCH 0610/1451] media: dvb-usb-v2: af9035: fix missing unlock Instead of returning an error, goto the mutex unlock at the end of the function. Fixes smatch warning: drivers/media/usb/dvb-usb-v2/af9035.c:467 af9035_i2c_master_xfer() warn: inconsistent returns '&d->i2c_mutex'. Locked on : 326,387 Unlocked on: 465,467 Signed-off-by: Hans Verkuil Fixes: 7bf744f2de0a ("media: dvb-usb-v2: af9035: Fix null-ptr-deref in af9035_i2c_master_xfer") Signed-off-by: Hans Verkuil --- drivers/media/usb/dvb-usb-v2/af9035.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 33a2aa8907e65..4eb7dd4599b7e 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -322,8 +322,10 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, ret = -EOPNOTSUPP; } else if ((msg[0].addr == state->af9033_i2c_addr[0]) || (msg[0].addr == state->af9033_i2c_addr[1])) { - if (msg[0].len < 3 || msg[1].len < 1) - return -EOPNOTSUPP; + if (msg[0].len < 3 || msg[1].len < 1) { + ret = -EOPNOTSUPP; + goto unlock; + } /* demod access via firmware interface */ u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | msg[0].buf[2]; @@ -383,8 +385,10 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, ret = -EOPNOTSUPP; } else if ((msg[0].addr == state->af9033_i2c_addr[0]) || (msg[0].addr == state->af9033_i2c_addr[1])) { - if (msg[0].len < 3) - return -EOPNOTSUPP; + if (msg[0].len < 3) { + ret = -EOPNOTSUPP; + goto unlock; + } /* demod access via firmware interface */ u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | msg[0].buf[2]; @@ -459,6 +463,7 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, ret = -EOPNOTSUPP; } +unlock: mutex_unlock(&d->i2c_mutex); if (ret < 0) -- GitLab From ada092e80c1031208df7366c7d3798d1e7d1904a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 6 Oct 2023 12:08:46 +0200 Subject: [PATCH 0611/1451] media: nxp: imx-jpeg: use goto instead of return For consistency use goto instead of return. This fixes a smatch warning: drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c:2792 mxc_jpeg_probe() warn: missing unwind goto? Signed-off-by: Hans Verkuil --- drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index e74b0ed8ec5ba..1fc6b3660bdd7 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -2789,7 +2789,7 @@ static int mxc_jpeg_probe(struct platform_device *pdev) ret = mxc_jpeg_attach_pm_domains(jpeg); if (ret < 0) { dev_err(dev, "failed to attach power domains %d\n", ret); - return ret; + goto err_clk; } /* v4l2 */ -- GitLab From 65b8c8cb2bf5f5676b5f0628a455c2982aa09683 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 6 Oct 2023 12:08:50 +0200 Subject: [PATCH 0612/1451] media: pci: mgb4: fix potential spectre vulnerability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix smatch warnings: drivers/media/pci/mgb4/mgb4_sysfs_out.c:118 video_source_store() warn: potential spectre issue 'mgbdev->vin' [r] (local cap) drivers/media/pci/mgb4/mgb4_sysfs_out.c:122 video_source_store() warn: possible spectre second half. 'loopin_new' Signed-off-by: Hans Verkuil Reviewed-by: Martin Tůma Signed-off-by: Hans Verkuil --- drivers/media/pci/mgb4/mgb4_sysfs_out.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/pci/mgb4/mgb4_sysfs_out.c b/drivers/media/pci/mgb4/mgb4_sysfs_out.c index 23a9aabf3915d..9f6e81c577267 100644 --- a/drivers/media/pci/mgb4/mgb4_sysfs_out.c +++ b/drivers/media/pci/mgb4/mgb4_sysfs_out.c @@ -8,6 +8,7 @@ */ #include +#include #include "mgb4_core.h" #include "mgb4_i2c.h" #include "mgb4_vout.h" @@ -114,8 +115,10 @@ static ssize_t video_source_store(struct device *dev, if (((config & 0xc) >> 2) < MGB4_VIN_DEVICES) loopin_old = mgbdev->vin[(config & 0xc) >> 2]; - if (val < MGB4_VIN_DEVICES) + if (val < MGB4_VIN_DEVICES) { + val = array_index_nospec(val, MGB4_VIN_DEVICES); loopin_new = mgbdev->vin[val]; + } if (loopin_old && loopin_cnt(loopin_old) == 1) mgb4_mask_reg(&mgbdev->video, loopin_old->config->regs.config, 0x2, 0x0); -- GitLab From be521bf7bfad4e4bd4c3e1d2853aeb563a1e51d6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 13 Oct 2023 09:43:55 +0200 Subject: [PATCH 0613/1451] media: pci: cx18: if cx == NULL, then don't use it. If the cx NULL pointer check is true, then it reports an error with CX18_ERR, but that uses cx. Replace it with pr_err. Reported by smatch: drivers/media/pci/cx18/cx18-mailbox.c:834 cx18_vapi() error: we previously assumed 'cx' could be null (see line 833) Signed-off-by: Hans Verkuil --- drivers/media/pci/cx18/cx18-mailbox.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/cx18/cx18-mailbox.c b/drivers/media/pci/cx18/cx18-mailbox.c index 3b283f3c67268..a6457c23d18c9 100644 --- a/drivers/media/pci/cx18/cx18-mailbox.c +++ b/drivers/media/pci/cx18/cx18-mailbox.c @@ -831,7 +831,7 @@ int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...) int i; if (cx == NULL) { - CX18_ERR("cx == NULL (cmd=%x)\n", cmd); + pr_err("cx == NULL (cmd=%x)\n", cmd); return 0; } if (args > MAX_MB_ARGUMENTS) { -- GitLab From feec1b29d7a81be3c1a0a0865eed67d05d4089c9 Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Tue, 3 Oct 2023 17:13:15 +0800 Subject: [PATCH 0614/1451] media: videobuf2: Fix IS_ERR checking in vb2_vmalloc_put_userptr() In order to avoid error pointers from frame_vector_pages(), we could use IS_ERR() to check the return value to fix this. This checking operation could make sure that vector contains pages. Signed-off-by: Ma Ke Acked-by: Tomasz Figa Signed-off-by: Hans Verkuil [hverkuil: add space between ){] Signed-off-by: Hans Verkuil --- drivers/media/common/videobuf2/videobuf2-vmalloc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c index 7c635e2921062..7d953706f3f80 100644 --- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c +++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c @@ -133,13 +133,15 @@ static void vb2_vmalloc_put_userptr(void *buf_priv) if (!buf->vec->is_pfns) { n_pages = frame_vector_count(buf->vec); - pages = frame_vector_pages(buf->vec); if (vaddr) vm_unmap_ram((void *)vaddr, n_pages); if (buf->dma_dir == DMA_FROM_DEVICE || - buf->dma_dir == DMA_BIDIRECTIONAL) - for (i = 0; i < n_pages; i++) - set_page_dirty_lock(pages[i]); + buf->dma_dir == DMA_BIDIRECTIONAL) { + pages = frame_vector_pages(buf->vec); + if (!WARN_ON_ONCE(IS_ERR(pages))) + for (i = 0; i < n_pages; i++) + set_page_dirty_lock(pages[i]); + } } else { iounmap((__force void __iomem *)buf->vaddr); } -- GitLab From 39377f84fb98561b86b645f0b7c33512eba7afaf Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 5 Oct 2023 16:51:16 +0200 Subject: [PATCH 0615/1451] media: verisilicon: Fixes clock list for rk3588 av1 decoder Mainlined RK3588 clock driver manage by itself the dependency between aclk/hclk and their root clocks (aclk_vdpu_root/hclk_vdpu_root). RK3588 av1 video decoder do not have to take care of it anymore so remove them from the list and be compliant with yaml bindings description. Fixes: 003afda97c65 ("media: verisilicon: Enable AV1 decoder on rk3588") Signed-off-by: Benjamin Gaignard Signed-off-by: Hans Verkuil --- drivers/media/platform/verisilicon/rockchip_vpu_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/verisilicon/rockchip_vpu_hw.c b/drivers/media/platform/verisilicon/rockchip_vpu_hw.c index 816ffa905a4bb..f975276707835 100644 --- a/drivers/media/platform/verisilicon/rockchip_vpu_hw.c +++ b/drivers/media/platform/verisilicon/rockchip_vpu_hw.c @@ -648,7 +648,7 @@ static const char * const rockchip_vpu_clk_names[] = { }; static const char * const rk3588_vpu981_vpu_clk_names[] = { - "aclk", "hclk", "aclk_vdpu_root", "hclk_vdpu_root" + "aclk", "hclk", }; /* VDPU1/VEPU1 */ -- GitLab From 900c06e9732859ff1be26dbb913b3c158ed15eb4 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 5 Oct 2023 18:11:07 +0200 Subject: [PATCH 0616/1451] dt-bindings: media: rockchip: Add resets property into decoder node RK3588 AV1 decoder hardware block have resets lines and driver code already support it. Update yaml file to be aligned with this feature. Signed-off-by: Benjamin Gaignard Acked-by: Krzysztof Kozlowski Signed-off-by: Hans Verkuil --- Documentation/devicetree/bindings/media/rockchip-vpu.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml index 772ec3283bc6c..c57e1f488895b 100644 --- a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml +++ b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml @@ -68,6 +68,13 @@ properties: iommus: maxItems: 1 + resets: + items: + - description: AXI reset line + - description: AXI bus interface unit reset line + - description: APB reset line + - description: APB bus interface unit reset line + required: - compatible - reg -- GitLab From 73e0538b4973df256962fda3aa0d89e6d0f79cd9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 6 Oct 2023 15:45:48 +0200 Subject: [PATCH 0617/1451] Documentation: media: gen-errors.rst: fix confusing ENOTTY description The text is very, very old and predates /dev/mediaX devices, so the reference to "media device" is today very confusing. It also says that the ioctl is not supported by the driver, but a driver may have multiple device nodes, some support a given ioctl, and some don't. Simplify the description: ENOTTY means that the ioctl is not supported by the file descriptor. Reported-by: Nicolas Dufresne Signed-off-by: Hans Verkuil Reviewed-by: Nicolas Dufresne Signed-off-by: Hans Verkuil --- Documentation/userspace-api/media/gen-errors.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Documentation/userspace-api/media/gen-errors.rst b/Documentation/userspace-api/media/gen-errors.rst index e595d0bea1095..4e8defd3612b0 100644 --- a/Documentation/userspace-api/media/gen-errors.rst +++ b/Documentation/userspace-api/media/gen-errors.rst @@ -59,9 +59,7 @@ Generic Error Codes - - ``ENOTTY`` - - The ioctl is not supported by the driver, actually meaning that - the required functionality is not available, or the file - descriptor is not for a media device. + - The ioctl is not supported by the file descriptor. - - ``ENOSPC`` -- GitLab From faaed02abfa941f33a87dc6eacbd015af9ab3cfa Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 6 Oct 2023 15:58:48 +0200 Subject: [PATCH 0618/1451] Documentation: media: buffer.rst: fix V4L2_BUF_FLAG_PREPARED The list of ioctls that set or clear this flag was garbled in the generator output. Put in the proper text. Signed-off-by: Hans Verkuil --- Documentation/userspace-api/media/v4l/buffer.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/buffer.rst b/Documentation/userspace-api/media/v4l/buffer.rst index 04dec3e570ede..52bbee81c0807 100644 --- a/Documentation/userspace-api/media/v4l/buffer.rst +++ b/Documentation/userspace-api/media/v4l/buffer.rst @@ -549,9 +549,9 @@ Buffer Flags - 0x00000400 - The buffer has been prepared for I/O and can be queued by the application. Drivers set or clear this flag when the - :ref:`VIDIOC_QUERYBUF`, + :ref:`VIDIOC_QUERYBUF `, :ref:`VIDIOC_PREPARE_BUF `, - :ref:`VIDIOC_QBUF` or + :ref:`VIDIOC_QBUF ` or :ref:`VIDIOC_DQBUF ` ioctl is called. * .. _`V4L2-BUF-FLAG-NO-CACHE-INVALIDATE`: -- GitLab From 32ec99f872aba071a070f61fcab2f3a068b50652 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Sat, 7 Oct 2023 16:43:39 +0800 Subject: [PATCH 0619/1451] media: aspeed: Drop unnecessary error check for debugfs_create_file() debugfs_create_file() return ERR_PTR and never return NULL. When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Fixes: 52fed10ad756 ("media: aspeed: add debugfs") Signed-off-by: Jinjie Ruan Suggested-by: Hans Verkuil Reviewed-by: Eddie James Signed-off-by: Hans Verkuil --- drivers/media/platform/aspeed/aspeed-video.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platform/aspeed/aspeed-video.c index a9c2c69b2ed99..d08aa7f73d4fb 100644 --- a/drivers/media/platform/aspeed/aspeed-video.c +++ b/drivers/media/platform/aspeed/aspeed-video.c @@ -1970,22 +1970,15 @@ static void aspeed_video_debugfs_remove(struct aspeed_video *video) debugfs_entry = NULL; } -static int aspeed_video_debugfs_create(struct aspeed_video *video) +static void aspeed_video_debugfs_create(struct aspeed_video *video) { debugfs_entry = debugfs_create_file(DEVICE_NAME, 0444, NULL, video, &aspeed_video_debugfs_fops); - if (!debugfs_entry) - aspeed_video_debugfs_remove(video); - - return !debugfs_entry ? -EIO : 0; } #else static void aspeed_video_debugfs_remove(struct aspeed_video *video) { } -static int aspeed_video_debugfs_create(struct aspeed_video *video) -{ - return 0; -} +static void aspeed_video_debugfs_create(struct aspeed_video *video) { } #endif /* CONFIG_DEBUG_FS */ static int aspeed_video_setup_video(struct aspeed_video *video) @@ -2198,9 +2191,7 @@ static int aspeed_video_probe(struct platform_device *pdev) return rc; } - rc = aspeed_video_debugfs_create(video); - if (rc) - dev_err(video->dev, "debugfs create failed\n"); + aspeed_video_debugfs_create(video); return 0; } -- GitLab From 19e2e01f30b5d2b448b5db097130486ea95af36f Mon Sep 17 00:00:00 2001 From: Irui Wang Date: Sat, 7 Oct 2023 19:33:47 +0800 Subject: [PATCH 0620/1451] media: mediatek: vcodec: Handle invalid encoder vsi Handle invalid encoder vsi in vpu_enc_init to ensure the encoder vsi is valid for future use. Fixes: 1972e32431ed ("media: mediatek: vcodec: Fix possible invalid memory access for encoder") Signed-off-by: Irui Wang Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Hans Verkuil --- drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c b/drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c index d299cc2962a5a..39e8f3ac53ca6 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c @@ -153,6 +153,11 @@ int vpu_enc_init(struct venc_vpu_inst *vpu) return -EINVAL; } + if (IS_ERR_OR_NULL(vpu->vsi)) { + mtk_venc_err(vpu->ctx, "invalid venc vsi"); + return -EINVAL; + } + return 0; } -- GitLab From 8cd08e365153481065eeec684ed00949bc980aff Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Sat, 7 Oct 2023 19:38:32 +0800 Subject: [PATCH 0621/1451] media: siano: Drop unnecessary error check for debugfs_create_dir/file() Both debugfs_create_dir() and debugfs_create_file() return ERR_PTR and never return NULL. As Hans suggested, this patch removes the error checking for both debugfs_create_dir() and debugfs_create_file() in smsdvb_debugfs_create(). This is because the DebugFS kernel API is developed in a way that the caller can safely ignore the errors that occur during the creation of DebugFS nodes. The debugfs APIs have a IS_ERR() judge in start_creating() which can handle it gracefully. So these checks are unnecessary. And as Hans pointed out, it's much better to first allocate debug_data before calling debugfs_create_dir, which need not to clean anything up in that case. Fixes: 503efe5cfc9f ("[media] siano: split debugfs code into a separate file") Signed-off-by: Jinjie Ruan Suggested-by: Hans Verkuil Signed-off-by: Hans Verkuil --- drivers/media/common/siano/smsdvb-debugfs.c | 22 ++++++--------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c index e0beefd80d7bc..73990e469df9d 100644 --- a/drivers/media/common/siano/smsdvb-debugfs.c +++ b/drivers/media/common/siano/smsdvb-debugfs.c @@ -353,31 +353,21 @@ static const struct file_operations debugfs_stats_ops = { int smsdvb_debugfs_create(struct smsdvb_client_t *client) { struct smscore_device_t *coredev = client->coredev; - struct dentry *d; struct smsdvb_debugfs *debug_data; if (!smsdvb_debugfs_usb_root || !coredev->is_usb_device) return -ENODEV; - client->debugfs = debugfs_create_dir(coredev->devpath, - smsdvb_debugfs_usb_root); - if (IS_ERR_OR_NULL(client->debugfs)) { - pr_info("Unable to create debugfs %s directory.\n", - coredev->devpath); - return -ENODEV; - } - - d = debugfs_create_file("stats", S_IRUGO | S_IWUSR, client->debugfs, - client, &debugfs_stats_ops); - if (!d) { - debugfs_remove(client->debugfs); - return -ENOMEM; - } - debug_data = kzalloc(sizeof(*client->debug_data), GFP_KERNEL); if (!debug_data) return -ENOMEM; + client->debugfs = debugfs_create_dir(coredev->devpath, + smsdvb_debugfs_usb_root); + + debugfs_create_file("stats", S_IRUGO | S_IWUSR, client->debugfs, + client, &debugfs_stats_ops); + client->debug_data = debug_data; client->prt_dvb_stats = smsdvb_print_dvb_stats; client->prt_isdb_stats = smsdvb_print_isdb_stats; -- GitLab From 63c5f1d8a8e571b2878405fa4b8e811cd0bb7f1a Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Sat, 7 Oct 2023 20:14:47 +0800 Subject: [PATCH 0622/1451] media: cx231xx: Use EP5_BUF_SIZE macro As Andrzej suggested, use EP5_BUF_SIZE macro to replace the other three places of 4096 in cx231xx with EP5_BUF_SIZE. Signed-off-by: Jinjie Ruan Suggested-by: Andrzej Pietrasiewicz Signed-off-by: Hans Verkuil --- drivers/media/usb/cx231xx/cx231xx-417.c | 9 ++++----- drivers/media/usb/cx231xx/cx231xx-core.c | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index c5e21785fafe2..fe4410a5e1284 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -937,7 +937,6 @@ static int cx231xx_load_firmware(struct cx231xx *dev) u32 *p_current_fw, *p_fw; u32 *p_fw_data; int frame = 0; - u16 _buffer_size = 4096; u8 *p_buffer; p_current_fw = vmalloc(1884180 * 4); @@ -947,7 +946,7 @@ static int cx231xx_load_firmware(struct cx231xx *dev) return -ENOMEM; } - p_buffer = vmalloc(4096); + p_buffer = vmalloc(EP5_BUF_SIZE); if (p_buffer == NULL) { dprintk(2, "FAIL!!!\n"); vfree(p_current_fw); @@ -1030,9 +1029,9 @@ static int cx231xx_load_firmware(struct cx231xx *dev) /*download the firmware by ep5-out*/ - for (frame = 0; frame < (int)(CX231xx_FIRM_IMAGE_SIZE*20/_buffer_size); + for (frame = 0; frame < (int)(CX231xx_FIRM_IMAGE_SIZE*20/EP5_BUF_SIZE); frame++) { - for (i = 0; i < _buffer_size; i++) { + for (i = 0; i < EP5_BUF_SIZE; i++) { *(p_buffer + i) = (u8)(*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x000000FF); i++; *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x0000FF00) >> 8); @@ -1041,7 +1040,7 @@ static int cx231xx_load_firmware(struct cx231xx *dev) i++; *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0xFF000000) >> 24); } - cx231xx_ep5_bulkout(dev, p_buffer, _buffer_size); + cx231xx_ep5_bulkout(dev, p_buffer, EP5_BUF_SIZE); } p_current_fw = p_fw; diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index 57a8b4780a7d6..7b7e2a26ef93b 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c @@ -993,7 +993,7 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets, /* De-allocates all pending stuff */ cx231xx_uninit_isoc(dev); - dma_q->p_left_data = kzalloc(4096, GFP_KERNEL); + dma_q->p_left_data = kzalloc(EP5_BUF_SIZE, GFP_KERNEL); if (dma_q->p_left_data == NULL) return -ENOMEM; -- GitLab From b833b178498dafa2156cfb6f4d3ce4581c21f1e5 Mon Sep 17 00:00:00 2001 From: Ming Qian Date: Mon, 9 Oct 2023 14:16:57 +0800 Subject: [PATCH 0623/1451] media: imx-jpeg: notify source chagne event when the first picture parsed After gstreamer rework the dynamic resolution change handling, gstreamer stop doing capture buffer allocation based on guesses and wait for the source change event when available. It requires driver always notify source change event in the initialization, even if the size parsed is equal to the size set on capture queue. otherwise, the pipeline will be stalled. Currently driver may not notify source change event if the parsed format and size are equal to those previously established, but it may stall the gstreamer pipeline. The link of gstreamer patch is https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4437 Fixes: b4e1fb8643da ("media: imx-jpeg: Support dynamic resolution change") Signed-off-by: Ming Qian Signed-off-by: Hans Verkuil --- drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c | 7 ++++++- drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index 1fc6b3660bdd7..64112b63298ca 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -1348,7 +1348,8 @@ static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx, q_data_cap = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); if (mxc_jpeg_compare_format(q_data_cap->fmt, jpeg_src_buf->fmt)) jpeg_src_buf->fmt = q_data_cap->fmt; - if (q_data_cap->fmt != jpeg_src_buf->fmt || + if (ctx->need_initial_source_change_evt || + q_data_cap->fmt != jpeg_src_buf->fmt || q_data_cap->w != jpeg_src_buf->w || q_data_cap->h != jpeg_src_buf->h) { dev_dbg(dev, "Detected jpeg res=(%dx%d)->(%dx%d), pixfmt=%c%c%c%c\n", @@ -1392,6 +1393,7 @@ static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx, mxc_jpeg_sizeimage(q_data_cap); notify_src_chg(ctx); ctx->source_change = 1; + ctx->need_initial_source_change_evt = false; if (vb2_is_streaming(v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx))) mxc_jpeg_set_last_buffer(ctx); } @@ -1611,6 +1613,9 @@ static int mxc_jpeg_queue_setup(struct vb2_queue *q, for (i = 0; i < *nplanes; i++) sizes[i] = mxc_jpeg_get_plane_size(q_data, i); + if (V4L2_TYPE_IS_OUTPUT(q->type)) + ctx->need_initial_source_change_evt = true; + return 0; } diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h index d80e94cc9d992..dc4afeeff5b65 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h @@ -99,6 +99,7 @@ struct mxc_jpeg_ctx { enum mxc_jpeg_enc_state enc_state; int slot; unsigned int source_change; + bool need_initial_source_change_evt; bool header_parsed; struct v4l2_ctrl_handler ctrl_handler; u8 jpeg_quality; -- GitLab From 56c0ac05a31a0bf525fddc300ea997356ad8146f Mon Sep 17 00:00:00 2001 From: Yunfei Dong Date: Tue, 10 Oct 2023 20:20:10 +0800 Subject: [PATCH 0624/1451] media: mediatek: vcodec: using encoder device to alloc/free encoder memory Need to use encoder device to allocate/free encoder memory when calling mtk_vcodec_mem_alloc/mtk_vcodec_mem_free, or leading to below crash log when test encoder with decoder device. pc : dma_alloc_attrs+0x44/0xf4 lr : mtk_vcodec_mem_alloc+0x50/0xa4 [mtk_vcodec_common] sp : ffffffc0209f3990 x29: ffffffc0209f39a0 x28: ffffff8024102a18 x27: 0000000000000000 x26: 0000000000000000 x25: ffffffc00c06e2d8 x24: 0000000000000001 x23: 0000000000000cc0 x22: 0000000000000010 x21: 0000000000000800 x20: ffffff8024102a18 x19: 0000000000000000 x18: 0000000000000000 x17: 0000000000000009 x16: ffffffe389736a98 x15: 0000000000000078 x14: ffffffe389704434 x13: 0000000000000007 x12: ffffffe38a2b2560 x11: 0000000000000800 x10: 0000000000000004 x9 : ffffffe331f07484 x8 : 5400e9aef2395000 x7 : 0000000000000000 x6 : 000000000000003f x5 : 0000000000000001 x4 : 0000000000000000 x3 : 0000000000000cc0 x2 : ffffff8024102a18 x1 : 0000000000000800 x0 : 0000000000000010 Call trace: dma_alloc_attrs+0x44/0xf4 mtk_vcodec_mem_alloc+0x50/0xa4 [mtk_vcodec_common 2819d3d601f3cd06c1f2213ac1b9995134441421] h264_enc_set_param+0x27c/0x378 [mtk_vcodec_enc 772cc3d26c254e8cf54079451ef8d930d2eb4404] venc_if_set_param+0x4c/0x7c [mtk_vcodec_enc 772cc3d26c254e8cf54079451ef8d930d2eb4404] vb2ops_venc_start_streaming+0x1bc/0x328 [mtk_vcodec_enc 772cc3d26c254e8cf54079451ef8d930d2eb4404] vb2_start_streaming+0x64/0x12c vb2_core_streamon+0x114/0x158 vb2_streamon+0x38/0x60 v4l2_m2m_streamon+0x48/0x88 v4l2_m2m_ioctl_streamon+0x20/0x2c v4l_streamon+0x2c/0x38 __video_do_ioctl+0x2c4/0x3dc video_usercopy+0x404/0x934 video_ioctl2+0x20/0x2c v4l2_ioctl+0x54/0x64 v4l2_compat_ioctl32+0x90/0xa34 __arm64_compat_sys_ioctl+0x128/0x13c invoke_syscall+0x4c/0x108 el0_svc_common+0x98/0x104 do_el0_svc_compat+0x28/0x34 el0_svc_compat+0x2c/0x74 el0t_32_sync_handler+0xa8/0xcc el0t_32_sync+0x194/0x198 Code: aa0003f6 aa0203f4 aa0103f5 f900 'Fixes: 01abf5fbb081c ("media: mediatek: vcodec: separate struct 'mtk_vcodec_ctx'")' Signed-off-by: Yunfei Dong Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Hans Verkuil --- .../mediatek/vcodec/common/mtk_vcodec_util.c | 56 +++++++++++++------ 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_util.c b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_util.c index 908602031fd0e..9ce34a3b5ee67 100644 --- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_util.c +++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_util.c @@ -47,20 +47,32 @@ EXPORT_SYMBOL(mtk_vcodec_write_vdecsys); int mtk_vcodec_mem_alloc(void *priv, struct mtk_vcodec_mem *mem) { + enum mtk_instance_type inst_type = *((unsigned int *)priv); + struct platform_device *plat_dev; unsigned long size = mem->size; - struct mtk_vcodec_dec_ctx *ctx = priv; - struct device *dev = &ctx->dev->plat_dev->dev; + int id; - mem->va = dma_alloc_coherent(dev, size, &mem->dma_addr, GFP_KERNEL); + if (inst_type == MTK_INST_ENCODER) { + struct mtk_vcodec_enc_ctx *enc_ctx = priv; + + plat_dev = enc_ctx->dev->plat_dev; + id = enc_ctx->id; + } else { + struct mtk_vcodec_dec_ctx *dec_ctx = priv; + + plat_dev = dec_ctx->dev->plat_dev; + id = dec_ctx->id; + } + + mem->va = dma_alloc_coherent(&plat_dev->dev, size, &mem->dma_addr, GFP_KERNEL); if (!mem->va) { - mtk_v4l2_vdec_err(ctx, "%s dma_alloc size=%ld failed!", dev_name(dev), size); + mtk_v4l2_err(plat_dev, "%s dma_alloc size=%ld failed!", + dev_name(&plat_dev->dev), size); return -ENOMEM; } - mtk_v4l2_vdec_dbg(3, ctx, "[%d] - va = %p", ctx->id, mem->va); - mtk_v4l2_vdec_dbg(3, ctx, "[%d] - dma = 0x%lx", ctx->id, - (unsigned long)mem->dma_addr); - mtk_v4l2_vdec_dbg(3, ctx, "[%d] size = 0x%lx", ctx->id, size); + mtk_v4l2_debug(plat_dev, 3, "[%d] - va = %p dma = 0x%lx size = 0x%lx", id, mem->va, + (unsigned long)mem->dma_addr, size); return 0; } @@ -68,21 +80,33 @@ EXPORT_SYMBOL(mtk_vcodec_mem_alloc); void mtk_vcodec_mem_free(void *priv, struct mtk_vcodec_mem *mem) { + enum mtk_instance_type inst_type = *((unsigned int *)priv); + struct platform_device *plat_dev; unsigned long size = mem->size; - struct mtk_vcodec_dec_ctx *ctx = priv; - struct device *dev = &ctx->dev->plat_dev->dev; + int id; + + if (inst_type == MTK_INST_ENCODER) { + struct mtk_vcodec_enc_ctx *enc_ctx = priv; + + plat_dev = enc_ctx->dev->plat_dev; + id = enc_ctx->id; + } else { + struct mtk_vcodec_dec_ctx *dec_ctx = priv; + + plat_dev = dec_ctx->dev->plat_dev; + id = dec_ctx->id; + } if (!mem->va) { - mtk_v4l2_vdec_err(ctx, "%s dma_free size=%ld failed!", dev_name(dev), size); + mtk_v4l2_err(plat_dev, "%s dma_free size=%ld failed!", + dev_name(&plat_dev->dev), size); return; } - mtk_v4l2_vdec_dbg(3, ctx, "[%d] - va = %p", ctx->id, mem->va); - mtk_v4l2_vdec_dbg(3, ctx, "[%d] - dma = 0x%lx", ctx->id, - (unsigned long)mem->dma_addr); - mtk_v4l2_vdec_dbg(3, ctx, "[%d] size = 0x%lx", ctx->id, size); + mtk_v4l2_debug(plat_dev, 3, "[%d] - va = %p dma = 0x%lx size = 0x%lx", id, mem->va, + (unsigned long)mem->dma_addr, size); - dma_free_coherent(dev, size, mem->va, mem->dma_addr); + dma_free_coherent(&plat_dev->dev, size, mem->va, mem->dma_addr); mem->va = NULL; mem->dma_addr = 0; mem->size = 0; -- GitLab From 2a76e7679b594ea3e1b3b7fb6c3d67158114020d Mon Sep 17 00:00:00 2001 From: Moudy Ho Date: Wed, 11 Oct 2023 11:00:37 +0800 Subject: [PATCH 0625/1451] media: platform: mtk-mdp3: fix uninitialized variable in mdp_path_config() Fix the build warnings that were detected by the linux-media build scripts tool: drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c: In function 'mdp_path_config.isra': drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c: warning: 'ctx' may be used uninitialized [-Wmaybe-uninitialized] | out = CFG_COMP(MT8195, ctx->param, outputs[0]); | ~~~^~~~~~~ drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h: note: in definition of macro 'CFG_COMP' | (IS_ERR_OR_NULL(comp) ? 0 : _CFG_COMP(plat, comp, mem)) | ^~~~ drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c: note: 'ctx' was declared here | struct mdp_comp_ctx *ctx; | Fixes: 61890ccaefaf ("media: platform: mtk-mdp3: add MediaTek MDP3 driver") Signed-off-by: Moudy Ho Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Hans Verkuil --- drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c index 3177592490bee..6adac857a4779 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c @@ -261,11 +261,11 @@ static int mdp_path_config(struct mdp_dev *mdp, struct mdp_cmdq_cmd *cmd, const struct v4l2_rect *compose; u32 out = 0; + ctx = &path->comps[index]; if (CFG_CHECK(MT8183, p_id)) out = CFG_COMP(MT8183, ctx->param, outputs[0]); compose = path->composes[out]; - ctx = &path->comps[index]; ret = call_op(ctx, config_frame, cmd, compose); if (ret) return ret; -- GitLab From 554df753a684ffef5be83aa8cbb35adaf6240bf3 Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Thu, 12 Oct 2023 15:45:19 +0800 Subject: [PATCH 0626/1451] media: videobuf2: Fix IS_ERR checking in vb2_dc_put_userptr() In order to avoid error pointers from frame_vector_pages(), we could use IS_ERR() to check the return value to fix this. This checking operation could make sure that vector contains pages. Signed-off-by: Ma Ke Acked-by: Tomasz Figa Signed-off-by: Hans Verkuil --- .../media/common/videobuf2/videobuf2-dma-contig.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index 2fa455d4a0480..3d4fd4ef53107 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -542,13 +542,14 @@ static void vb2_dc_put_userptr(void *buf_priv) */ dma_unmap_sgtable(buf->dev, sgt, buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC); - pages = frame_vector_pages(buf->vec); - /* sgt should exist only if vector contains pages... */ - BUG_ON(IS_ERR(pages)); if (buf->dma_dir == DMA_FROM_DEVICE || - buf->dma_dir == DMA_BIDIRECTIONAL) - for (i = 0; i < frame_vector_count(buf->vec); i++) - set_page_dirty_lock(pages[i]); + buf->dma_dir == DMA_BIDIRECTIONAL) { + pages = frame_vector_pages(buf->vec); + /* sgt should exist only if vector contains pages... */ + if (!WARN_ON_ONCE(IS_ERR(pages))) + for (i = 0; i < frame_vector_count(buf->vec); i++) + set_page_dirty_lock(pages[i]); + } sg_free_table(sgt); kfree(sgt); } else { -- GitLab From 94e27fbeca27d8c772fc2bc807730aaee5886055 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 12 Oct 2023 12:35:25 +0200 Subject: [PATCH 0627/1451] media: cec: meson: always include meson sub-directory in Makefile 'meson' directory contains two separate drivers, so it should be added to Makefile compilation hierarchy unconditionally, because otherwise the meson-ao-cec-g12a won't be compiled if meson-ao-cec is not selected. Signed-off-by: Marek Szyprowski Fixes: 4be5e8648b0c ("media: move CEC platform drivers to a separate directory") Signed-off-by: Hans Verkuil --- drivers/media/cec/platform/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/cec/platform/Makefile b/drivers/media/cec/platform/Makefile index 26d2bc7783944..a51e98ab4958d 100644 --- a/drivers/media/cec/platform/Makefile +++ b/drivers/media/cec/platform/Makefile @@ -6,7 +6,7 @@ # Please keep it in alphabetic order obj-$(CONFIG_CEC_CROS_EC) += cros-ec/ obj-$(CONFIG_CEC_GPIO) += cec-gpio/ -obj-$(CONFIG_CEC_MESON_AO) += meson/ +obj-y += meson/ obj-$(CONFIG_CEC_SAMSUNG_S5P) += s5p/ obj-$(CONFIG_CEC_SECO) += seco/ obj-$(CONFIG_CEC_STI) += sti/ -- GitLab From 787650cc335201a0489905c5504a9179470ebc51 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 13 Oct 2023 20:04:12 -0700 Subject: [PATCH 0628/1451] Input: Annotate struct ff_device with __counted_by Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct ff_device. Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20231006201739.work.350-kees@kernel.org Signed-off-by: Dmitry Torokhov --- include/linux/input.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/input.h b/include/linux/input.h index 49790c1bd2c43..de6503c0edb8e 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -562,7 +562,7 @@ struct ff_device { int max_effects; struct ff_effect *effects; - struct file *effect_owners[]; + struct file *effect_owners[] __counted_by(max_effects); }; int input_ff_create(struct input_dev *dev, unsigned int max_effects); -- GitLab From 6cd256694afe2a0a94f62418fea95279de2b7ada Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 13 Oct 2023 20:09:33 -0700 Subject: [PATCH 0629/1451] Input: tegra-kbc - use device_get_match_data() Use preferred device_get_match_data() instead of of_match_device() to get the driver match data. With this, adjust the includes to explicitly include the correct headers. Signed-off-by: Rob Herring Acked-by: Thierry Reding Link: https://lore.kernel.org/r/20231006224432.442709-1-robh@kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tegra-kbc.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index c9a823ea45d02..a1765ed8c825c 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -602,9 +602,6 @@ static int tegra_kbc_probe(struct platform_device *pdev) unsigned int debounce_cnt; unsigned int scan_time_rows; unsigned int keymap_rows; - const struct of_device_id *match; - - match = of_match_device(tegra_kbc_of_match, &pdev->dev); kbc = devm_kzalloc(&pdev->dev, sizeof(*kbc), GFP_KERNEL); if (!kbc) { @@ -613,7 +610,7 @@ static int tegra_kbc_probe(struct platform_device *pdev) } kbc->dev = &pdev->dev; - kbc->hw_support = match->data; + kbc->hw_support = device_get_match_data(&pdev->dev); kbc->max_keys = kbc->hw_support->max_rows * kbc->hw_support->max_columns; kbc->num_rows_and_columns = kbc->hw_support->max_rows + -- GitLab From dd712d3d45807db9fcae28a522deee85c1f2fde6 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 22 Aug 2023 13:19:46 -0700 Subject: [PATCH 0630/1451] kgdb: Flush console before entering kgdb on panic When entering kdb/kgdb on a kernel panic, it was be observed that the console isn't flushed before the `kdb` prompt came up. Specifically, when using the buddy lockup detector on arm64 and running: echo HARDLOCKUP > /sys/kernel/debug/provoke-crash/DIRECT I could see: [ 26.161099] lkdtm: Performing direct entry HARDLOCKUP [ 32.499881] watchdog: Watchdog detected hard LOCKUP on cpu 6 [ 32.552865] Sending NMI from CPU 5 to CPUs 6: [ 32.557359] NMI backtrace for cpu 6 ... [backtrace for cpu 6] ... [ 32.558353] NMI backtrace for cpu 5 ... [backtrace for cpu 5] ... [ 32.867471] Sending NMI from CPU 5 to CPUs 0-4,7: [ 32.872321] NMI backtrace forP cpuANC: Hard LOCKUP Entering kdb (current=..., pid 0) on processor 5 due to Keyboard Entry [5]kdb> As you can see, backtraces for the other CPUs start printing and get interleaved with the kdb PANIC print. Let's replicate the commands to flush the console in the kdb panic entry point to avoid this. Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/20230822131945.1.I5b460ae8f954e4c4f628a373d6e74713c06dd26f@changeid Signed-off-by: Daniel Thompson --- kernel/debug/debug_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c index 621037a0aa870..ce1bb2301c061 100644 --- a/kernel/debug/debug_core.c +++ b/kernel/debug/debug_core.c @@ -1006,6 +1006,9 @@ void kgdb_panic(const char *msg) if (panic_timeout) return; + debug_locks_off(); + console_flush_on_panic(CONSOLE_FLUSH_PENDING); + if (dbg_kdb_mode) kdb_printf("PANIC: %s\n", msg); -- GitLab From c61c255e114c52682546447ed44d3470b5708134 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Mon, 16 Oct 2023 11:28:27 +0800 Subject: [PATCH 0631/1451] iommu/vt-d: Remove unused function The function are defined in the pasid.c file, but not called elsewhere, so delete the unused function. drivers/iommu/intel/pasid.c:342:20: warning: unused function 'pasid_set_wpe'. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=6185 Signed-off-by: Jiapeng Chong Link: https://lore.kernel.org/r/20230818091603.64800-1-jiapeng.chong@linux.alibaba.com Signed-off-by: Lu Baolu Signed-off-by: Joerg Roedel --- drivers/iommu/intel/pasid.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c index 8f92b92f3d2ab..06ddb3c927f52 100644 --- a/drivers/iommu/intel/pasid.c +++ b/drivers/iommu/intel/pasid.c @@ -335,15 +335,6 @@ static inline void pasid_set_fault_enable(struct pasid_entry *pe) pasid_set_bits(&pe->val[0], 1 << 1, 0); } -/* - * Setup the WPE(Write Protect Enable) field (Bit 132) of a - * scalable mode PASID entry. - */ -static inline void pasid_set_wpe(struct pasid_entry *pe) -{ - pasid_set_bits(&pe->val[2], 1 << 4, 1 << 4); -} - /* * Setup the P(Present) field (Bit 0) of a scalable mode PASID * entry. -- GitLab From e8aa45f8cc2c3afe2a3608ea7220bbdb516bef07 Mon Sep 17 00:00:00 2001 From: Jingqi Liu Date: Mon, 16 Oct 2023 11:28:28 +0800 Subject: [PATCH 0632/1451] iommu/vt-d: debugfs: Dump entry pointing to huge page For the page table entry pointing to a huge page, the data below the level of the huge page is meaningless and does not need to be dumped. Signed-off-by: Jingqi Liu Link: https://lore.kernel.org/r/20231013135811.73953-2-Jingqi.liu@intel.com Signed-off-by: Lu Baolu Signed-off-by: Joerg Roedel --- drivers/iommu/intel/debugfs.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/intel/debugfs.c b/drivers/iommu/intel/debugfs.c index 1f925285104ee..497c1561d3d21 100644 --- a/drivers/iommu/intel/debugfs.c +++ b/drivers/iommu/intel/debugfs.c @@ -311,9 +311,14 @@ static inline unsigned long level_to_directory_size(int level) static inline void dump_page_info(struct seq_file *m, unsigned long iova, u64 *path) { - seq_printf(m, "0x%013lx |\t0x%016llx\t0x%016llx\t0x%016llx\t0x%016llx\t0x%016llx\n", - iova >> VTD_PAGE_SHIFT, path[5], path[4], - path[3], path[2], path[1]); + seq_printf(m, "0x%013lx |\t0x%016llx\t0x%016llx\t0x%016llx", + iova >> VTD_PAGE_SHIFT, path[5], path[4], path[3]); + if (path[2]) { + seq_printf(m, "\t0x%016llx", path[2]); + if (path[1]) + seq_printf(m, "\t0x%016llx", path[1]); + } + seq_putc(m, '\n'); } static void pgtable_walk_level(struct seq_file *m, struct dma_pte *pde, -- GitLab From d87731f609318a27e9aa3d01cf97798599d32839 Mon Sep 17 00:00:00 2001 From: Jingqi Liu Date: Mon, 16 Oct 2023 11:28:29 +0800 Subject: [PATCH 0633/1451] iommu/vt-d: debugfs: Create/remove debugfs file per {device, pasid} Add a debugfs directory per pair of {device, pasid} if the mappings of its page table are created and destroyed by the iommu_map/unmap() interfaces. i.e. /sys/kernel/debug/iommu/intel//. Create a debugfs file in the directory for users to dump the page table corresponding to {device, pasid}. e.g. /sys/kernel/debug/iommu/intel/0000:00:02.0/1/domain_translation_struct. For the default domain without pasid, it creates a debugfs file in the debugfs device directory for users to dump its page table. e.g. /sys/kernel/debug/iommu/intel/0000:00:02.0/domain_translation_struct. When setting a domain to a PASID of device, create a debugfs file in the pasid debugfs directory for users to dump the page table of the specified pasid. Remove the debugfs device directory of the device when releasing a device. e.g. /sys/kernel/debug/iommu/intel/0000:00:01.0 Signed-off-by: Jingqi Liu Link: https://lore.kernel.org/r/20231013135811.73953-3-Jingqi.liu@intel.com Signed-off-by: Lu Baolu Signed-off-by: Joerg Roedel --- drivers/iommu/intel/debugfs.c | 53 +++++++++++++++++++++++++++++++---- drivers/iommu/intel/iommu.c | 7 +++++ drivers/iommu/intel/iommu.h | 14 +++++++++ 3 files changed, 69 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/intel/debugfs.c b/drivers/iommu/intel/debugfs.c index 497c1561d3d21..8a18a7be52152 100644 --- a/drivers/iommu/intel/debugfs.c +++ b/drivers/iommu/intel/debugfs.c @@ -111,6 +111,8 @@ static const struct iommu_regset iommu_regs_64[] = { IOMMU_REGSET_ENTRY(VCRSP), }; +static struct dentry *intel_iommu_debug; + static int iommu_regset_show(struct seq_file *m, void *unused) { struct dmar_drhd_unit *drhd; @@ -671,16 +673,12 @@ static const struct file_operations dmar_perf_latency_fops = { void __init intel_iommu_debugfs_init(void) { - struct dentry *intel_iommu_debug = debugfs_create_dir("intel", - iommu_debugfs_dir); + intel_iommu_debug = debugfs_create_dir("intel", iommu_debugfs_dir); debugfs_create_file("iommu_regset", 0444, intel_iommu_debug, NULL, &iommu_regset_fops); debugfs_create_file("dmar_translation_struct", 0444, intel_iommu_debug, NULL, &dmar_translation_struct_fops); - debugfs_create_file("domain_translation_struct", 0444, - intel_iommu_debug, NULL, - &domain_translation_struct_fops); debugfs_create_file("invalidation_queue", 0444, intel_iommu_debug, NULL, &invalidation_queue_fops); #ifdef CONFIG_IRQ_REMAP @@ -690,3 +688,48 @@ void __init intel_iommu_debugfs_init(void) debugfs_create_file("dmar_perf_latency", 0644, intel_iommu_debug, NULL, &dmar_perf_latency_fops); } + +/* + * Create a debugfs directory for each device, and then create a + * debugfs file in this directory for users to dump the page table + * of the default domain. e.g. + * /sys/kernel/debug/iommu/intel/0000:00:01.0/domain_translation_struct + */ +void intel_iommu_debugfs_create_dev(struct device_domain_info *info) +{ + info->debugfs_dentry = debugfs_create_dir(dev_name(info->dev), intel_iommu_debug); + + debugfs_create_file("domain_translation_struct", 0444, info->debugfs_dentry, + NULL, &domain_translation_struct_fops); +} + +/* Remove the device debugfs directory. */ +void intel_iommu_debugfs_remove_dev(struct device_domain_info *info) +{ + debugfs_remove_recursive(info->debugfs_dentry); +} + +/* + * Create a debugfs directory per pair of {device, pasid}, then create the + * corresponding debugfs file in this directory for users to dump its page + * table. e.g. + * /sys/kernel/debug/iommu/intel/0000:00:01.0/1/domain_translation_struct + * + * The debugfs only dumps the page tables whose mappings are created and + * destroyed by the iommu_map/unmap() interfaces. Check the mapping type + * of the domain before creating debugfs directory. + */ +void intel_iommu_debugfs_create_dev_pasid(struct dev_pasid_info *dev_pasid) +{ + struct device_domain_info *info = dev_iommu_priv_get(dev_pasid->dev); + char dir_name[10]; + + sprintf(dir_name, "%x", dev_pasid->pasid); + dev_pasid->debugfs_dentry = debugfs_create_dir(dir_name, info->debugfs_dentry); +} + +/* Remove the device pasid debugfs directory. */ +void intel_iommu_debugfs_remove_dev_pasid(struct dev_pasid_info *dev_pasid) +{ + debugfs_remove_recursive(dev_pasid->debugfs_dentry); +} diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 5db283c17e0dc..a42916354ed4c 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -4425,6 +4425,8 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev) } } + intel_iommu_debugfs_create_dev(info); + return &iommu->iommu; } @@ -4434,6 +4436,7 @@ static void intel_iommu_release_device(struct device *dev) dmar_remove_one_dev_info(dev); intel_pasid_free_table(dev); + intel_iommu_debugfs_remove_dev(info); dev_iommu_priv_set(dev, NULL); kfree(info); set_dma_ops(dev, NULL); @@ -4726,6 +4729,7 @@ static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid) spin_unlock_irqrestore(&dmar_domain->lock, flags); domain_detach_iommu(dmar_domain, iommu); + intel_iommu_debugfs_remove_dev_pasid(dev_pasid); kfree(dev_pasid); out_tear_down: intel_pasid_tear_down_entry(iommu, dev, pasid, false); @@ -4778,6 +4782,9 @@ static int intel_iommu_set_dev_pasid(struct iommu_domain *domain, list_add(&dev_pasid->link_domain, &dmar_domain->dev_pasids); spin_unlock_irqrestore(&dmar_domain->lock, flags); + if (domain->type & __IOMMU_DOMAIN_PAGING) + intel_iommu_debugfs_create_dev_pasid(dev_pasid); + return 0; out_detach_iommu: domain_detach_iommu(dmar_domain, iommu); diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h index c18fb699c87ac..43ecda2ac11db 100644 --- a/drivers/iommu/intel/iommu.h +++ b/drivers/iommu/intel/iommu.h @@ -716,12 +716,18 @@ struct device_domain_info { struct intel_iommu *iommu; /* IOMMU used by this device */ struct dmar_domain *domain; /* pointer to domain */ struct pasid_table *pasid_table; /* pasid table */ +#ifdef CONFIG_INTEL_IOMMU_DEBUGFS + struct dentry *debugfs_dentry; /* pointer to device directory dentry */ +#endif }; struct dev_pasid_info { struct list_head link_domain; /* link to domain siblings */ struct device *dev; ioasid_t pasid; +#ifdef CONFIG_INTEL_IOMMU_DEBUGFS + struct dentry *debugfs_dentry; /* pointer to pasid directory dentry */ +#endif }; static inline void __iommu_flush_cache( @@ -883,8 +889,16 @@ static inline void intel_svm_remove_dev_pasid(struct device *dev, ioasid_t pasid #ifdef CONFIG_INTEL_IOMMU_DEBUGFS void intel_iommu_debugfs_init(void); +void intel_iommu_debugfs_create_dev(struct device_domain_info *info); +void intel_iommu_debugfs_remove_dev(struct device_domain_info *info); +void intel_iommu_debugfs_create_dev_pasid(struct dev_pasid_info *dev_pasid); +void intel_iommu_debugfs_remove_dev_pasid(struct dev_pasid_info *dev_pasid); #else static inline void intel_iommu_debugfs_init(void) {} +static inline void intel_iommu_debugfs_create_dev(struct device_domain_info *info) {} +static inline void intel_iommu_debugfs_remove_dev(struct device_domain_info *info) {} +static inline void intel_iommu_debugfs_create_dev_pasid(struct dev_pasid_info *dev_pasid) {} +static inline void intel_iommu_debugfs_remove_dev_pasid(struct dev_pasid_info *dev_pasid) {} #endif /* CONFIG_INTEL_IOMMU_DEBUGFS */ extern const struct attribute_group *intel_iommu_groups[]; -- GitLab From 2b437e80456654df3980706384065d444f4bb54d Mon Sep 17 00:00:00 2001 From: Jingqi Liu Date: Mon, 16 Oct 2023 11:28:30 +0800 Subject: [PATCH 0634/1451] iommu/vt-d: debugfs: Support dumping a specified page table The original debugfs only dumps all page tables without pasid. With pasid supported, the page table with pasid also needs to be dumped. This patch supports dumping a specified page table in legacy mode or scalable mode with or without a specified pasid. For legacy mode, according to bus number and DEVFN, traverse the root table and context table to get the pointer of page table in the context table entry, then dump the specified page table. For scalable mode, according to bus number, DEVFN and pasid, traverse the root table, context table, pasid directory and pasid table to get the pointer of page table in the pasid table entry, then dump the specified page table.. Examples are as follows: 1) Dump the page table of device "0000:00:1f.0" that only supports legacy mode. $ sudo cat /sys/kernel/debug/iommu/intel/0000:00:1f.0/domain_translation_struct 2) Dump the page table of device "0000:00:0a.0" with PASID "1" that supports scalable mode. $ sudo cat /sys/kernel/debug/iommu/intel/0000:00:0a.0/1/domain_translation_struct Suggested-by: Kevin Tian Signed-off-by: Jingqi Liu Link: https://lore.kernel.org/r/20231013135811.73953-4-Jingqi.liu@intel.com Signed-off-by: Lu Baolu Signed-off-by: Joerg Roedel --- drivers/iommu/intel/debugfs.c | 153 ++++++++++++++++++++++++++-------- 1 file changed, 119 insertions(+), 34 deletions(-) diff --git a/drivers/iommu/intel/debugfs.c b/drivers/iommu/intel/debugfs.c index 8a18a7be52152..dee61e513be6d 100644 --- a/drivers/iommu/intel/debugfs.c +++ b/drivers/iommu/intel/debugfs.c @@ -347,58 +347,140 @@ static void pgtable_walk_level(struct seq_file *m, struct dma_pte *pde, } } -static int __show_device_domain_translation(struct device *dev, void *data) +static int domain_translation_struct_show(struct seq_file *m, + struct device_domain_info *info, + ioasid_t pasid) { - struct dmar_domain *domain; - struct seq_file *m = data; - u64 path[6] = { 0 }; - - domain = to_dmar_domain(iommu_get_domain_for_dev(dev)); - if (!domain) - return 0; + bool scalable, found = false; + struct dmar_drhd_unit *drhd; + struct intel_iommu *iommu; + u16 devfn, bus, seg; - seq_printf(m, "Device %s @0x%llx\n", dev_name(dev), - (u64)virt_to_phys(domain->pgd)); - seq_puts(m, "IOVA_PFN\t\tPML5E\t\t\tPML4E\t\t\tPDPE\t\t\tPDE\t\t\tPTE\n"); + bus = info->bus; + devfn = info->devfn; + seg = info->segment; - pgtable_walk_level(m, domain->pgd, domain->agaw + 2, 0, path); - seq_putc(m, '\n'); + rcu_read_lock(); + for_each_active_iommu(iommu, drhd) { + struct context_entry *context; + u64 pgd, path[6] = { 0 }; + u32 sts, agaw; - /* Don't iterate */ - return 1; -} + if (seg != iommu->segment) + continue; -static int show_device_domain_translation(struct device *dev, void *data) -{ - struct iommu_group *group; + sts = dmar_readl(iommu->reg + DMAR_GSTS_REG); + if (!(sts & DMA_GSTS_TES)) { + seq_printf(m, "DMA Remapping is not enabled on %s\n", + iommu->name); + continue; + } + if (dmar_readq(iommu->reg + DMAR_RTADDR_REG) & DMA_RTADDR_SMT) + scalable = true; + else + scalable = false; - group = iommu_group_get(dev); - if (group) { /* - * The group->mutex is held across the callback, which will - * block calls to iommu_attach/detach_group/device. Hence, + * The iommu->lock is held across the callback, which will + * block calls to domain_attach/domain_detach. Hence, * the domain of the device will not change during traversal. * - * All devices in an iommu group share a single domain, hence - * we only dump the domain of the first device. Even though, - * this code still possibly races with the iommu_unmap() + * Traversing page table possibly races with the iommu_unmap() * interface. This could be solved by RCU-freeing the page * table pages in the iommu_unmap() path. */ - iommu_group_for_each_dev(group, data, - __show_device_domain_translation); - iommu_group_put(group); + spin_lock(&iommu->lock); + + context = iommu_context_addr(iommu, bus, devfn, 0); + if (!context || !context_present(context)) + goto iommu_unlock; + + if (scalable) { /* scalable mode */ + struct pasid_entry *pasid_tbl, *pasid_tbl_entry; + struct pasid_dir_entry *dir_tbl, *dir_entry; + u16 dir_idx, tbl_idx, pgtt; + u64 pasid_dir_ptr; + + pasid_dir_ptr = context->lo & VTD_PAGE_MASK; + + /* Dump specified device domain mappings with PASID. */ + dir_idx = pasid >> PASID_PDE_SHIFT; + tbl_idx = pasid & PASID_PTE_MASK; + + dir_tbl = phys_to_virt(pasid_dir_ptr); + dir_entry = &dir_tbl[dir_idx]; + + pasid_tbl = get_pasid_table_from_pde(dir_entry); + if (!pasid_tbl) + goto iommu_unlock; + + pasid_tbl_entry = &pasid_tbl[tbl_idx]; + if (!pasid_pte_is_present(pasid_tbl_entry)) + goto iommu_unlock; + + /* + * According to PASID Granular Translation Type(PGTT), + * get the page table pointer. + */ + pgtt = (u16)(pasid_tbl_entry->val[0] & GENMASK_ULL(8, 6)) >> 6; + agaw = (u8)(pasid_tbl_entry->val[0] & GENMASK_ULL(4, 2)) >> 2; + + switch (pgtt) { + case PASID_ENTRY_PGTT_FL_ONLY: + pgd = pasid_tbl_entry->val[2]; + break; + case PASID_ENTRY_PGTT_SL_ONLY: + case PASID_ENTRY_PGTT_NESTED: + pgd = pasid_tbl_entry->val[0]; + break; + default: + goto iommu_unlock; + } + pgd &= VTD_PAGE_MASK; + } else { /* legacy mode */ + pgd = context->lo & VTD_PAGE_MASK; + agaw = context->hi & 7; + } + + seq_printf(m, "Device %04x:%02x:%02x.%x ", + iommu->segment, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + + if (scalable) + seq_printf(m, "with pasid %x @0x%llx\n", pasid, pgd); + else + seq_printf(m, "@0x%llx\n", pgd); + + seq_printf(m, "%-17s\t%-18s\t%-18s\t%-18s\t%-18s\t%-s\n", + "IOVA_PFN", "PML5E", "PML4E", "PDPE", "PDE", "PTE"); + pgtable_walk_level(m, phys_to_virt(pgd), agaw + 2, 0, path); + + found = true; +iommu_unlock: + spin_unlock(&iommu->lock); + if (found) + break; } + rcu_read_unlock(); return 0; } -static int domain_translation_struct_show(struct seq_file *m, void *unused) +static int dev_domain_translation_struct_show(struct seq_file *m, void *unused) { - return bus_for_each_dev(&pci_bus_type, NULL, m, - show_device_domain_translation); + struct device_domain_info *info = (struct device_domain_info *)m->private; + + return domain_translation_struct_show(m, info, IOMMU_NO_PASID); } -DEFINE_SHOW_ATTRIBUTE(domain_translation_struct); +DEFINE_SHOW_ATTRIBUTE(dev_domain_translation_struct); + +static int pasid_domain_translation_struct_show(struct seq_file *m, void *unused) +{ + struct dev_pasid_info *dev_pasid = (struct dev_pasid_info *)m->private; + struct device_domain_info *info = dev_iommu_priv_get(dev_pasid->dev); + + return domain_translation_struct_show(m, info, dev_pasid->pasid); +} +DEFINE_SHOW_ATTRIBUTE(pasid_domain_translation_struct); static void invalidation_queue_entry_show(struct seq_file *m, struct intel_iommu *iommu) @@ -700,7 +782,7 @@ void intel_iommu_debugfs_create_dev(struct device_domain_info *info) info->debugfs_dentry = debugfs_create_dir(dev_name(info->dev), intel_iommu_debug); debugfs_create_file("domain_translation_struct", 0444, info->debugfs_dentry, - NULL, &domain_translation_struct_fops); + info, &dev_domain_translation_struct_fops); } /* Remove the device debugfs directory. */ @@ -726,6 +808,9 @@ void intel_iommu_debugfs_create_dev_pasid(struct dev_pasid_info *dev_pasid) sprintf(dir_name, "%x", dev_pasid->pasid); dev_pasid->debugfs_dentry = debugfs_create_dir(dir_name, info->debugfs_dentry); + + debugfs_create_file("domain_translation_struct", 0444, dev_pasid->debugfs_dentry, + dev_pasid, &pasid_domain_translation_struct_fops); } /* Remove the device pasid debugfs directory. */ -- GitLab From 9e13ec61de2a51195b122a79461431d8cb99d7b5 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 9 Oct 2023 12:24:27 -0600 Subject: [PATCH 0635/1451] iommu/virtio: Add __counted_by for struct viommu_request and use struct_size() Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). While there, use struct_size() helper, instead of the open-coded version, to calculate the size for the allocation of the whole flexible structure, including of course, the flexible-array member. This code was found with the help of Coccinelle, and audited and fixed manually. Signed-off-by: Gustavo A. R. Silva Reviewed-by: Jean-Philippe Brucker Reviewed-by: Justin Stitt Link: https://lore.kernel.org/r/ZSRFW0yDlDo8+at3@work Signed-off-by: Joerg Roedel --- drivers/iommu/virtio-iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/virtio-iommu.c b/drivers/iommu/virtio-iommu.c index 17dcd826f5c20..379ebe03efb6d 100644 --- a/drivers/iommu/virtio-iommu.c +++ b/drivers/iommu/virtio-iommu.c @@ -85,7 +85,7 @@ struct viommu_request { void *writeback; unsigned int write_offset; unsigned int len; - char buf[]; + char buf[] __counted_by(len); }; #define VIOMMU_FAULT_RESV_MASK 0xffffff00 @@ -230,7 +230,7 @@ static int __viommu_add_req(struct viommu_dev *viommu, void *buf, size_t len, if (write_offset <= 0) return -EINVAL; - req = kzalloc(sizeof(*req) + len, GFP_ATOMIC); + req = kzalloc(struct_size(req, buf, len), GFP_ATOMIC); if (!req) return -ENOMEM; -- GitLab From 058b4d9de86b3f77cd23fbd43a0f5ee4ea8e0aeb Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 11 Oct 2023 11:01:21 +0300 Subject: [PATCH 0636/1451] iommu: change iommu_map_sgtable to return signed values The iommu_map_sgtable() function returns ssize_t and negative error codes but it's declared as size_t instead. I think that static checkers would have complained if this caused a bug, but even though it doesn't cause a bug, it's definitely worth fixing. Signed-off-by: Dan Carpenter Reviewed-by: Lu Baolu Link: https://lore.kernel.org/r/06672b96-23fd-424c-8880-1626e7bf119c@moroto.mountain Signed-off-by: Joerg Roedel --- include/linux/iommu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 64bd20142cbed..c28178f3690a8 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -1116,7 +1116,7 @@ static inline void iommu_free_global_pasid(ioasid_t pasid) {} * Creates a mapping at @iova for the buffer described by a scatterlist * stored in the given sg_table object in the provided IOMMU domain. */ -static inline size_t iommu_map_sgtable(struct iommu_domain *domain, +static inline ssize_t iommu_map_sgtable(struct iommu_domain *domain, unsigned long iova, struct sg_table *sgt, int prot) { return iommu_map_sg(domain, iova, sgt->sgl, sgt->orig_nents, prot, -- GitLab From cedc811c76778bdef91d405717acee0de54d8db5 Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Mon, 16 Oct 2023 05:13:05 +0000 Subject: [PATCH 0637/1451] iommu/amd: Remove DMA_FQ type from domain allocation path .. as drivers won't see DMA_FQ any more. See commit a4fdd9762272 ("iommu: Use flush queue capability") for details. Suggested-by: Robin Murphy Signed-off-by: Vasant Hegde Link: https://lore.kernel.org/r/20231016051305.13091-1-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/iommu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index d996a6f22a5fc..a284768cb542b 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -2148,7 +2148,6 @@ static struct protection_domain *protection_domain_alloc(unsigned int type) case IOMMU_DOMAIN_IDENTITY: return domain; case IOMMU_DOMAIN_DMA: - case IOMMU_DOMAIN_DMA_FQ: pgtable = amd_iommu_pgtable; break; /* -- GitLab From 406a849926f3e4c1fcedfdc6623a33bc4f13adbe Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Sep 2023 10:53:16 +0200 Subject: [PATCH 0638/1451] MAINTAINER: Create entry for Renesas SH-Mobile DRM drivers Split off DRM drivers for Renesas SH-Mobile into its own entry, and add Geert Uytterhoeven as a maintainer. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/7cbcec72214886b67afa8d724a9245661d8cd675.1694767208.git.geert+renesas@glider.be --- MAINTAINERS | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index e05506ea89170..e12c73b8a69d8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7016,7 +7016,7 @@ F: drivers/gpu/host1x/ F: include/linux/host1x.h F: include/uapi/drm/tegra_drm.h -DRM DRIVERS FOR RENESAS +DRM DRIVERS FOR RENESAS R-CAR M: Laurent Pinchart M: Kieran Bingham L: dri-devel@lists.freedesktop.org @@ -7027,7 +7027,15 @@ F: Documentation/devicetree/bindings/display/bridge/renesas,dsi-csi2-tx.yaml F: Documentation/devicetree/bindings/display/bridge/renesas,dw-hdmi.yaml F: Documentation/devicetree/bindings/display/bridge/renesas,lvds.yaml F: Documentation/devicetree/bindings/display/renesas,du.yaml -F: drivers/gpu/drm/renesas/ +F: drivers/gpu/drm/renesas/rcar-du/ + +DRM DRIVERS FOR RENESAS SHMOBILE +M: Laurent Pinchart +M: Geert Uytterhoeven +L: dri-devel@lists.freedesktop.org +L: linux-renesas-soc@vger.kernel.org +S: Supported +F: drivers/gpu/drm/renesas/shmobile/ F: include/linux/platform_data/shmob_drm.h DRM DRIVERS FOR ROCKCHIP -- GitLab From 613676ec42d59784670f70b4e09db23531d3e29a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Sep 2023 10:53:17 +0200 Subject: [PATCH 0639/1451] dt-bindings: display: Add Renesas SH-Mobile LCDC bindings Add device tree bindings for the LCD Controller (LCDC) found in Renesas SuperH SH-Mobile and ARM SH/R-Mobile SOCs. Based on a plain text prototype by Laurent Pinchart. Reviewed-by: Rob Herring Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/6d0a053502abd6555e9a6cbe055e1bdc3329999d.1694767208.git.geert+renesas@glider.be --- .../display/renesas,shmobile-lcdc.yaml | 130 ++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 131 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/renesas,shmobile-lcdc.yaml diff --git a/Documentation/devicetree/bindings/display/renesas,shmobile-lcdc.yaml b/Documentation/devicetree/bindings/display/renesas,shmobile-lcdc.yaml new file mode 100644 index 0000000000000..9816c4cacc7d9 --- /dev/null +++ b/Documentation/devicetree/bindings/display/renesas,shmobile-lcdc.yaml @@ -0,0 +1,130 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/renesas,shmobile-lcdc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas SH-Mobile LCD Controller (LCDC) + +maintainers: + - Laurent Pinchart + - Geert Uytterhoeven + +properties: + compatible: + enum: + - renesas,r8a7740-lcdc # R-Mobile A1 + - renesas,sh73a0-lcdc # SH-Mobile AG5 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 5 + description: + Only the functional clock is mandatory. + Some of the optional clocks are model-dependent (e.g. "video" (a.k.a. + "vou" or "dv_clk") is available on R-Mobile A1 only). + + clock-names: + minItems: 1 + items: + - const: fck + - enum: [ media, lclk, hdmi, video ] + - enum: [ media, lclk, hdmi, video ] + - enum: [ media, lclk, hdmi, video ] + - enum: [ media, lclk, hdmi, video ] + + power-domains: + maxItems: 1 + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: LCD port (R-Mobile A1 and SH-Mobile AG5) + unevaluatedProperties: false + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: HDMI port (R-Mobile A1 LCDC1 and SH-Mobile AG5) + unevaluatedProperties: false + + port@2: + $ref: /schemas/graph.yaml#/properties/port + description: MIPI-DSI port (SH-Mobile AG5) + unevaluatedProperties: false + + required: + - port@0 + + unevaluatedProperties: false + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - power-domains + - ports + +additionalProperties: false + +allOf: + - if: + properties: + compatible: + contains: + const: renesas,r8a7740-lcdc + then: + properties: + ports: + properties: + port@2: false + + - if: + properties: + compatible: + contains: + const: renesas,sh73a0-lcdc + then: + properties: + ports: + required: + - port@1 + - port@2 + +examples: + - | + #include + #include + + lcd-controller@fe940000 { + compatible = "renesas,r8a7740-lcdc"; + reg = <0xfe940000 0x4000>; + interrupts = ; + clocks = <&mstp1_clks R8A7740_CLK_LCDC0>, + <&cpg_clocks R8A7740_CLK_M3>, <&lcdlclk0_clk>, + <&vou_clk>; + clock-names = "fck", "media", "lclk", "video"; + power-domains = <&pd_a4lc>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + lcdc0_rgb: endpoint { + }; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index e12c73b8a69d8..c5f67ee3e6f29 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7035,6 +7035,7 @@ M: Geert Uytterhoeven L: dri-devel@lists.freedesktop.org L: linux-renesas-soc@vger.kernel.org S: Supported +F: Documentation/devicetree/bindings/display/renesas,shmobile-lcdc.yaml F: drivers/gpu/drm/renesas/shmobile/ F: include/linux/platform_data/shmob_drm.h -- GitLab From c68ab8b5ea53aa0895f7ec5b72c87e0f7097761e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Sep 2023 10:53:18 +0200 Subject: [PATCH 0640/1451] media: uapi: Add MEDIA_BUS_FMT_RGB666_2X9_BE format Add the RGB666 9:9 format MEDIA_BUS_FMT_RGB666_2X9_BE, which is supported by the SH-Mobile LCD Controller. Reviewed-by: Laurent Pinchart Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/8b421cc391ac511c07cb1e243c1ba18bb95f7f98.1694767209.git.geert+renesas@glider.be --- .../media/v4l/subdev-formats.rst | 72 +++++++++++++++++++ include/uapi/linux/media-bus-format.h | 3 +- 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/Documentation/userspace-api/media/v4l/subdev-formats.rst b/Documentation/userspace-api/media/v4l/subdev-formats.rst index a3a35eeed7084..eb3cd20b0cf2e 100644 --- a/Documentation/userspace-api/media/v4l/subdev-formats.rst +++ b/Documentation/userspace-api/media/v4l/subdev-formats.rst @@ -949,6 +949,78 @@ The following tables list existing packed RGB formats. - b\ :sub:`2` - b\ :sub:`1` - b\ :sub:`0` + * .. _MEDIA-BUS-FMT-RGB666-2X9-BE: + + - MEDIA_BUS_FMT_RGB666_2X9_BE + - 0x1025 + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + * - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` * .. _MEDIA-BUS-FMT-BGR666-1X18: - MEDIA_BUS_FMT_BGR666_1X18 diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h index a03c543cb072d..f05f747e444d6 100644 --- a/include/uapi/linux/media-bus-format.h +++ b/include/uapi/linux/media-bus-format.h @@ -34,7 +34,7 @@ #define MEDIA_BUS_FMT_FIXED 0x0001 -/* RGB - next is 0x1025 */ +/* RGB - next is 0x1026 */ #define MEDIA_BUS_FMT_RGB444_1X12 0x1016 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002 @@ -46,6 +46,7 @@ #define MEDIA_BUS_FMT_RGB565_2X8_BE 0x1007 #define MEDIA_BUS_FMT_RGB565_2X8_LE 0x1008 #define MEDIA_BUS_FMT_RGB666_1X18 0x1009 +#define MEDIA_BUS_FMT_RGB666_2X9_BE 0x1025 #define MEDIA_BUS_FMT_BGR666_1X18 0x1023 #define MEDIA_BUS_FMT_RBG888_1X24 0x100e #define MEDIA_BUS_FMT_RGB666_1X24_CPADHI 0x1015 -- GitLab From 28675d45a3810c7302979b9803b18814d357c650 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Sep 2023 10:53:19 +0200 Subject: [PATCH 0641/1451] drm: renesas: shmobile: Fix overlay plane disable Merely writing zero to the CHn Source Image Format Register is not sufficient to disable a plane, as the programmed register value is not propagated immediately to the current side. This can be seen when using the -P option of modetest: the extra plane is displayed correctly, but does not disappear after exit. Fix this by doing the full update dance using the Blend Control Register, like is done when enabling the plane. Reviewed-by: Laurent Pinchart Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/54e2556e18b5524ce153a7ac79faf2c7b0a55260.1694767209.git.geert+renesas@glider.be --- drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c index 850986cee8482..0e34573c3cb3d 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c @@ -215,7 +215,10 @@ static int shmob_drm_plane_disable(struct drm_plane *plane, splane->format = NULL; + lcdc_write(sdev, LDBCR, LDBCR_UPC(splane->index)); lcdc_write(sdev, LDBnBSIFR(splane->index), 0); + lcdc_write(sdev, LDBCR, + LDBCR_UPF(splane->index) | LDBCR_UPD(splane->index)); return 0; } -- GitLab From 1396c2693aed3fb3240aa54dde61085958bbab97 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Sep 2023 10:53:20 +0200 Subject: [PATCH 0642/1451] drm: renesas: shmobile: Fix ARGB32 overlay format typo When configuring a CHn Source Image Format Register (LDBBSIFR), one should use the corresponding LDBBSIFR_RPKF_* definition for overlay planes, not the DDFR_PKF_* definition for the primary plane. Fortunately both definitions resolve to the same value, so this bug did not cause any harm. Reviewed-by: Laurent Pinchart Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/34f8d51539c048e264699ca869ad9d7a952cd69f.1694767209.git.geert+renesas@glider.be --- drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c index 0e34573c3cb3d..7e49e2873da1b 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c @@ -94,10 +94,10 @@ static void __shmob_drm_plane_setup(struct shmob_drm_plane *splane, format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB24; break; case DRM_FORMAT_ARGB8888: - format |= LDBBSIFR_AL_PK | LDBBSIFR_RY | LDDFR_PKF_ARGB32; + format |= LDBBSIFR_AL_PK | LDBBSIFR_RY | LDBBSIFR_RPKF_ARGB32; break; case DRM_FORMAT_XRGB8888: - format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDDFR_PKF_ARGB32; + format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_ARGB32; break; case DRM_FORMAT_NV12: case DRM_FORMAT_NV21: -- GitLab From b25064ef997bf30ad8c6abe5fbd6e3ddae75d17b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Sep 2023 10:53:21 +0200 Subject: [PATCH 0643/1451] drm: renesas: shmobile: Correct encoder/connector types The first encoder output on the SH-Mobile LCD Controller is a DPI parallel bus. However, at the time of introduction of the driver, no encoder or connector types were defined yet for the DPI parallel bus, hence the driver used the ones for LVDS instead. Adjust the types accordingly. Reviewed-by: Laurent Pinchart Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/db500dd8356955d3471a1ccd68d90db9f9750ef9.1694767209.git.geert+renesas@glider.be --- drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c index 11dd2bc803e7c..fbfd906844da4 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c @@ -598,7 +598,7 @@ int shmob_drm_encoder_create(struct shmob_drm_device *sdev) encoder->possible_crtcs = 1; ret = drm_simple_encoder_init(sdev->ddev, encoder, - DRM_MODE_ENCODER_LVDS); + DRM_MODE_ENCODER_DPI); if (ret < 0) return ret; @@ -684,7 +684,7 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev, connector->display_info.height_mm = sdev->pdata->panel.height_mm; ret = drm_connector_init(sdev->ddev, connector, &connector_funcs, - DRM_MODE_CONNECTOR_LVDS); + DRM_MODE_CONNECTOR_DPI); if (ret < 0) return ret; -- GitLab From 616f73c9d3255342a037c5204ce381a4d7aa274a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Sep 2023 10:53:22 +0200 Subject: [PATCH 0644/1451] drm: renesas: shmobile: Add support for Runtime PM The SH-Mobile LCD Controller is part of a PM Domain on all relevant SoCs (clock domain on all, power domain on some). Hence it may not be sufficient to manage the LCDC module clock explicitly (e.g. if the selected clock source differs from SHMOB_DRM_CLK_BUS). Fix this by using Runtime PM for all clock handling. Add an explicit dependency on CONFIG_PM, which should already be met on all affected platforms. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/e7359a64963bd9a4f1531c2beae850774ce140bc.1694767209.git.geert+renesas@glider.be --- drivers/gpu/drm/renesas/shmobile/Kconfig | 2 +- .../gpu/drm/renesas/shmobile/shmob_drm_crtc.c | 32 ++-------------- .../gpu/drm/renesas/shmobile/shmob_drm_drv.c | 38 +++++++++++++++++-- 3 files changed, 40 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/renesas/shmobile/Kconfig b/drivers/gpu/drm/renesas/shmobile/Kconfig index ad14112999ad8..ba941587ca70e 100644 --- a/drivers/gpu/drm/renesas/shmobile/Kconfig +++ b/drivers/gpu/drm/renesas/shmobile/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 config DRM_SHMOBILE tristate "DRM Support for SH Mobile" - depends on DRM + depends on DRM && PM depends on ARCH_RENESAS || ARCH_SHMOBILE || COMPILE_TEST select BACKLIGHT_CLASS_DEVICE select DRM_KMS_HELPER diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c index fbfd906844da4..2d9ae0c6ab7b1 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -34,29 +35,6 @@ * TODO: panel support */ -/* ----------------------------------------------------------------------------- - * Clock management - */ - -static int shmob_drm_clk_on(struct shmob_drm_device *sdev) -{ - int ret; - - if (sdev->clock) { - ret = clk_prepare_enable(sdev->clock); - if (ret < 0) - return ret; - } - - return 0; -} - -static void shmob_drm_clk_off(struct shmob_drm_device *sdev) -{ - if (sdev->clock) - clk_disable_unprepare(sdev->clock); -} - /* ----------------------------------------------------------------------------- * CRTC */ @@ -170,9 +148,8 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc) if (WARN_ON(format == NULL)) return; - /* Enable clocks before accessing the hardware. */ - ret = shmob_drm_clk_on(sdev); - if (ret < 0) + ret = pm_runtime_resume_and_get(sdev->dev); + if (ret) return; /* Reset and enable the LCDC. */ @@ -268,8 +245,7 @@ static void shmob_drm_crtc_stop(struct shmob_drm_crtc *scrtc) /* Disable the display output. */ lcdc_write(sdev, LDCNT1R, 0); - /* Stop clocks. */ - shmob_drm_clk_off(sdev); + pm_runtime_put(sdev->dev); scrtc->started = false; } diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c index e5db4e0095bad..a0f8b7666ab33 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -165,8 +166,35 @@ static int shmob_drm_pm_resume(struct device *dev) return 0; } -static DEFINE_SIMPLE_DEV_PM_OPS(shmob_drm_pm_ops, - shmob_drm_pm_suspend, shmob_drm_pm_resume); +static int shmob_drm_pm_runtime_suspend(struct device *dev) +{ + struct shmob_drm_device *sdev = dev_get_drvdata(dev); + + if (sdev->clock) + clk_disable_unprepare(sdev->clock); + + return 0; +} + +static int shmob_drm_pm_runtime_resume(struct device *dev) +{ + struct shmob_drm_device *sdev = dev_get_drvdata(dev); + int ret; + + if (sdev->clock) { + ret = clk_prepare_enable(sdev->clock); + if (ret < 0) + return ret; + } + + return 0; +} + +static const struct dev_pm_ops shmob_drm_pm_ops = { + SYSTEM_SLEEP_PM_OPS(shmob_drm_pm_suspend, shmob_drm_pm_resume) + RUNTIME_PM_OPS(shmob_drm_pm_runtime_suspend, + shmob_drm_pm_runtime_resume, NULL) +}; /* ----------------------------------------------------------------------------- * Platform driver @@ -218,6 +246,10 @@ static int shmob_drm_probe(struct platform_device *pdev) if (ret < 0) return ret; + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret) + return ret; + ret = shmob_drm_init_interface(sdev); if (ret < 0) return ret; @@ -289,7 +321,7 @@ static struct platform_driver shmob_drm_platform_driver = { .remove_new = shmob_drm_remove, .driver = { .name = "shmob-drm", - .pm = pm_sleep_ptr(&shmob_drm_pm_ops), + .pm = &shmob_drm_pm_ops, }, }; -- GitLab From 887042d635005b5127b04a73d2c9d0c79cf380b1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Sep 2023 10:53:23 +0200 Subject: [PATCH 0645/1451] drm: renesas: shmobile: Restore indentation of shmob_drm_setup_clocks() Commit 56550d94cbaeaa19 ("Drivers: gpu: remove __dev* attributes.") forgot to realign the continuation of the parameter section of shmob_drm_setup_clocks(). Reviewed-by: Laurent Pinchart Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/b1c5c9b33b74fef1f4250847398a98f93c4dc1be.1694767209.git.geert+renesas@glider.be --- drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c index a0f8b7666ab33..8a685bfc8e08e 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c @@ -67,7 +67,7 @@ static int shmob_drm_init_interface(struct shmob_drm_device *sdev) } static int shmob_drm_setup_clocks(struct shmob_drm_device *sdev, - enum shmob_drm_clk_source clksrc) + enum shmob_drm_clk_source clksrc) { struct clk *clk; char *clkname; -- GitLab From 480b5571f33151e9b4a4dfddfbde7eff14fbe27d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Sep 2023 10:53:24 +0200 Subject: [PATCH 0646/1451] drm: renesas: shmobile: Use %p4cc to print fourcc code Replace the last printing of an hexadecimal fourcc format code by a pretty-printed format name, using the "%p4cc" format specifier. Reviewed-by: Laurent Pinchart Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/aaa9d474535f3cd800da5a9ef27023dc7960e690.1694767209.git.geert+renesas@glider.be --- drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c index 7e49e2873da1b..36fedb2b74c8b 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c @@ -184,8 +184,8 @@ shmob_drm_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, format = shmob_drm_format_info(fb->format->format); if (format == NULL) { - dev_dbg(sdev->dev, "update_plane: unsupported format %08x\n", - fb->format->format); + dev_dbg(sdev->dev, "update_plane: unsupported format %p4cc\n", + &fb->format->format); return -EINVAL; } -- GitLab From 02e6e3c2fa26ad1e9b458b07c8fd0e56d46607bd Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Sep 2023 10:53:25 +0200 Subject: [PATCH 0647/1451] drm: renesas: shmobile: Add missing YCbCr formats The primary plane supports various YCbCr formats, and the CRTC code already knows how to handle them. Enable support for the missing formats by adding them to the table of supported modes. Reviewed-by: Laurent Pinchart Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/e5a5d5ab2083280be5fcdc428e8b8ca198b4448d.1694767209.git.geert+renesas@glider.be --- drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c index 2d9ae0c6ab7b1..a0e1a49c84d56 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c @@ -460,6 +460,12 @@ static const uint32_t modeset_formats[] = { DRM_FORMAT_RGB888, DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888, + DRM_FORMAT_NV12, + DRM_FORMAT_NV21, + DRM_FORMAT_NV16, + DRM_FORMAT_NV61, + DRM_FORMAT_NV24, + DRM_FORMAT_NV42, }; static const struct drm_plane_funcs primary_plane_funcs = { -- GitLab From 7802ca6b234b622da35fa4843943be7a0e8facf1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Sep 2023 10:53:26 +0200 Subject: [PATCH 0648/1451] drm: renesas: shmobile: Improve shmob_drm_format_info table Improve the table containing hardware information related to the supported plane formats: 1. Move (part of) the overlay format register settings from multiple switch() statements spread across the code into the table, like is already done for the primary plane register settings, 2. Remove the .yuv field, as that information can easily be extracted from the register settings using a new helper macro, 3. Shrink and move the .bpp field to reduce table size. Reviewed-by: Laurent Pinchart Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/b41f755e80ffe5fb4adbb2d8f96f2073de5c33bc.1694767209.git.geert+renesas@glider.be --- .../gpu/drm/renesas/shmobile/shmob_drm_crtc.c | 29 ++-------- .../gpu/drm/renesas/shmobile/shmob_drm_kms.c | 42 ++++++++++---- .../gpu/drm/renesas/shmobile/shmob_drm_kms.h | 9 ++- .../drm/renesas/shmobile/shmob_drm_plane.c | 56 ++----------------- 4 files changed, 47 insertions(+), 89 deletions(-) diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c index a0e1a49c84d56..2cdf8f9b06e5f 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c @@ -191,31 +191,12 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc) lcdc_write(sdev, LDDFR, format->lddfr | LDDFR_CF1); lcdc_write(sdev, LDMLSR, scrtc->line_size); lcdc_write(sdev, LDSA1R, scrtc->dma[0]); - if (format->yuv) + if (shmob_drm_format_is_yuv(format)) lcdc_write(sdev, LDSA2R, scrtc->dma[1]); lcdc_write(sdev, LDSM1R, 0); /* Word and long word swap. */ - switch (format->fourcc) { - case DRM_FORMAT_RGB565: - case DRM_FORMAT_NV21: - case DRM_FORMAT_NV61: - case DRM_FORMAT_NV42: - value = LDDDSR_LS | LDDDSR_WS; - break; - case DRM_FORMAT_RGB888: - case DRM_FORMAT_NV12: - case DRM_FORMAT_NV16: - case DRM_FORMAT_NV24: - value = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS; - break; - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_XRGB8888: - default: - value = LDDDSR_LS; - break; - } - lcdc_write(sdev, LDDDSR, value); + lcdc_write(sdev, LDDDSR, format->ldddsr); /* Setup planes. */ drm_for_each_legacy_plane(plane, dev) { @@ -271,12 +252,12 @@ static void shmob_drm_crtc_compute_base(struct shmob_drm_crtc *scrtc, struct drm_gem_dma_object *gem; unsigned int bpp; - bpp = scrtc->format->yuv ? 8 : scrtc->format->bpp; + bpp = shmob_drm_format_is_yuv(scrtc->format) ? 8 : scrtc->format->bpp; gem = drm_fb_dma_get_gem_obj(fb, 0); scrtc->dma[0] = gem->dma_addr + fb->offsets[0] + y * fb->pitches[0] + x * bpp / 8; - if (scrtc->format->yuv) { + if (shmob_drm_format_is_yuv(scrtc->format)) { bpp = scrtc->format->bpp - 8; gem = drm_fb_dma_get_gem_obj(fb, 1); scrtc->dma[1] = gem->dma_addr + fb->offsets[1] @@ -293,7 +274,7 @@ static void shmob_drm_crtc_update_base(struct shmob_drm_crtc *scrtc) shmob_drm_crtc_compute_base(scrtc, crtc->x, crtc->y); lcdc_write_mirror(sdev, LDSA1R, scrtc->dma[0]); - if (scrtc->format->yuv) + if (shmob_drm_format_is_yuv(scrtc->format)) lcdc_write_mirror(sdev, LDSA2R, scrtc->dma[1]); lcdc_write(sdev, LDRCNTR, lcdc_read(sdev, LDRCNTR) ^ LDRCNTR_MRS); diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c index 99381cc0abf3a..8fd360149743f 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c @@ -27,53 +27,73 @@ static const struct shmob_drm_format_info shmob_drm_format_infos[] = { { .fourcc = DRM_FORMAT_RGB565, .bpp = 16, - .yuv = false, .lddfr = LDDFR_PKF_RGB16, + .ldddsr = LDDDSR_LS | LDDDSR_WS, + .ldbbsifr = LDBBSIFR_AL_1 | LDBBSIFR_SWPL | LDBBSIFR_SWPW | + LDBBSIFR_RY | LDBBSIFR_RPKF_RGB16, }, { .fourcc = DRM_FORMAT_RGB888, .bpp = 24, - .yuv = false, .lddfr = LDDFR_PKF_RGB24, + .ldddsr = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS, + .ldbbsifr = LDBBSIFR_AL_1 | LDBBSIFR_SWPL | LDBBSIFR_SWPW | + LDBBSIFR_SWPB | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB24, }, { .fourcc = DRM_FORMAT_ARGB8888, .bpp = 32, - .yuv = false, .lddfr = LDDFR_PKF_ARGB32, + .ldddsr = LDDDSR_LS, + .ldbbsifr = LDBBSIFR_AL_PK | LDBBSIFR_SWPL | LDBBSIFR_RY | + LDBBSIFR_RPKF_ARGB32, }, { .fourcc = DRM_FORMAT_XRGB8888, .bpp = 32, - .yuv = false, .lddfr = LDDFR_PKF_ARGB32, + .ldddsr = LDDDSR_LS, + .ldbbsifr = LDBBSIFR_AL_1 | LDBBSIFR_SWPL | LDBBSIFR_RY | + LDBBSIFR_RPKF_ARGB32, }, { .fourcc = DRM_FORMAT_NV12, .bpp = 12, - .yuv = true, .lddfr = LDDFR_CC | LDDFR_YF_420, + .ldddsr = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS, + .ldbbsifr = LDBBSIFR_AL_1 | LDBBSIFR_SWPL | LDBBSIFR_SWPW | + LDBBSIFR_SWPB | LDBBSIFR_CHRR_420, }, { .fourcc = DRM_FORMAT_NV21, .bpp = 12, - .yuv = true, .lddfr = LDDFR_CC | LDDFR_YF_420, + .ldddsr = LDDDSR_LS | LDDDSR_WS, + .ldbbsifr = LDBBSIFR_AL_1 | LDBBSIFR_SWPL | LDBBSIFR_SWPW | + LDBBSIFR_CHRR_420, }, { .fourcc = DRM_FORMAT_NV16, .bpp = 16, - .yuv = true, .lddfr = LDDFR_CC | LDDFR_YF_422, + .ldddsr = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS, + .ldbbsifr = LDBBSIFR_AL_1 | LDBBSIFR_SWPL | LDBBSIFR_SWPW | + LDBBSIFR_SWPB | LDBBSIFR_CHRR_422, }, { .fourcc = DRM_FORMAT_NV61, .bpp = 16, - .yuv = true, .lddfr = LDDFR_CC | LDDFR_YF_422, + .ldddsr = LDDDSR_LS | LDDDSR_WS, + .ldbbsifr = LDBBSIFR_AL_1 | LDBBSIFR_SWPL | LDBBSIFR_SWPW | + LDBBSIFR_CHRR_422, }, { .fourcc = DRM_FORMAT_NV24, .bpp = 24, - .yuv = true, .lddfr = LDDFR_CC | LDDFR_YF_444, + .ldddsr = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS, + .ldbbsifr = LDBBSIFR_AL_1 | LDBBSIFR_SWPL | LDBBSIFR_SWPW | + LDBBSIFR_SWPB | LDBBSIFR_CHRR_444, }, { .fourcc = DRM_FORMAT_NV42, .bpp = 24, - .yuv = true, .lddfr = LDDFR_CC | LDDFR_YF_444, + .ldddsr = LDDDSR_LS | LDDDSR_WS, + .ldbbsifr = LDBBSIFR_AL_1 | LDBBSIFR_SWPL | LDBBSIFR_SWPW | + LDBBSIFR_CHRR_444, }, }; @@ -112,7 +132,7 @@ shmob_drm_fb_create(struct drm_device *dev, struct drm_file *file_priv, return ERR_PTR(-EINVAL); } - if (format->yuv) { + if (shmob_drm_format_is_yuv(format)) { unsigned int chroma_cpp = format->bpp == 24 ? 2 : 1; if (mode_cmd->pitches[1] != mode_cmd->pitches[0] * chroma_cpp) { diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.h b/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.h index 0347b1fd2338a..590162c3db202 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.h +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.h @@ -17,11 +17,14 @@ struct shmob_drm_device; struct shmob_drm_format_info { u32 fourcc; - unsigned int bpp; - bool yuv; - u32 lddfr; + u32 lddfr; /* LCD Data Format Register */ + u16 ldbbsifr; /* CHn Source Image Format Register low bits */ + u8 ldddsr; /* LCDC Input Image Data Swap Register low bits */ + u8 bpp; }; +#define shmob_drm_format_is_yuv(format) ((format)->lddfr & LDDFR_CC) + const struct shmob_drm_format_info *shmob_drm_format_info(u32 fourcc); int shmob_drm_modeset_init(struct shmob_drm_device *sdev); diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c index 36fedb2b74c8b..0b2ab153e9ae7 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c @@ -43,12 +43,12 @@ static void shmob_drm_plane_compute_base(struct shmob_drm_plane *splane, struct drm_gem_dma_object *gem; unsigned int bpp; - bpp = splane->format->yuv ? 8 : splane->format->bpp; + bpp = shmob_drm_format_is_yuv(splane->format) ? 8 : splane->format->bpp; gem = drm_fb_dma_get_gem_obj(fb, 0); splane->dma[0] = gem->dma_addr + fb->offsets[0] + y * fb->pitches[0] + x * bpp / 8; - if (splane->format->yuv) { + if (shmob_drm_format_is_yuv(splane->format)) { bpp = splane->format->bpp - 8; gem = drm_fb_dma_get_gem_obj(fb, 1); splane->dma[1] = gem->dma_addr + fb->offsets[1] @@ -64,54 +64,8 @@ static void __shmob_drm_plane_setup(struct shmob_drm_plane *splane, u32 format; /* TODO: Support ROP3 mode */ - format = LDBBSIFR_EN | (splane->alpha << LDBBSIFR_LAY_SHIFT); - - switch (splane->format->fourcc) { - case DRM_FORMAT_RGB565: - case DRM_FORMAT_NV21: - case DRM_FORMAT_NV61: - case DRM_FORMAT_NV42: - format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW; - break; - case DRM_FORMAT_RGB888: - case DRM_FORMAT_NV12: - case DRM_FORMAT_NV16: - case DRM_FORMAT_NV24: - format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW | LDBBSIFR_SWPB; - break; - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_XRGB8888: - default: - format |= LDBBSIFR_SWPL; - break; - } - - switch (splane->format->fourcc) { - case DRM_FORMAT_RGB565: - format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB16; - break; - case DRM_FORMAT_RGB888: - format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB24; - break; - case DRM_FORMAT_ARGB8888: - format |= LDBBSIFR_AL_PK | LDBBSIFR_RY | LDBBSIFR_RPKF_ARGB32; - break; - case DRM_FORMAT_XRGB8888: - format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_ARGB32; - break; - case DRM_FORMAT_NV12: - case DRM_FORMAT_NV21: - format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_420; - break; - case DRM_FORMAT_NV16: - case DRM_FORMAT_NV61: - format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_422; - break; - case DRM_FORMAT_NV24: - case DRM_FORMAT_NV42: - format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_444; - break; - } + format = LDBBSIFR_EN | (splane->alpha << LDBBSIFR_LAY_SHIFT) | + splane->format->ldbbsifr; #define plane_reg_dump(sdev, splane, reg) \ dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x 0x%08x\n", __func__, \ @@ -144,7 +98,7 @@ static void __shmob_drm_plane_setup(struct shmob_drm_plane *splane, shmob_drm_plane_compute_base(splane, fb, splane->src_x, splane->src_y); lcdc_write(sdev, LDBnBSAYR(splane->index), splane->dma[0]); - if (splane->format->yuv) + if (shmob_drm_format_is_yuv(splane->format)) lcdc_write(sdev, LDBnBSACR(splane->index), splane->dma[1]); lcdc_write(sdev, LDBCR, -- GitLab From 0da28d5fc808dfcfbc910870b4b0277c1a7ccb6c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 15 Sep 2023 10:53:27 +0200 Subject: [PATCH 0649/1451] drm: renesas: shmobile: Remove backlight support Backlight support should be implemented by panels, not by the LCDC driver. As the feature is currently unused anyway, remove it. Signed-off-by: Laurent Pinchart [geert: Cleanups] Reviewed-by: Laurent Pinchart Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/69707650245bc2193d072f24723d4d5482ea590b.1694767209.git.geert+renesas@glider.be --- drivers/gpu/drm/renesas/shmobile/Makefile | 3 +- .../renesas/shmobile/shmob_drm_backlight.c | 82 ------------------- .../renesas/shmobile/shmob_drm_backlight.h | 19 ----- .../gpu/drm/renesas/shmobile/shmob_drm_crtc.c | 33 +------- .../gpu/drm/renesas/shmobile/shmob_drm_crtc.h | 8 -- .../gpu/drm/renesas/shmobile/shmob_drm_drv.h | 2 +- .../gpu/drm/renesas/shmobile/shmob_drm_kms.c | 2 +- include/linux/platform_data/shmob_drm.h | 8 -- 8 files changed, 7 insertions(+), 150 deletions(-) delete mode 100644 drivers/gpu/drm/renesas/shmobile/shmob_drm_backlight.c delete mode 100644 drivers/gpu/drm/renesas/shmobile/shmob_drm_backlight.h diff --git a/drivers/gpu/drm/renesas/shmobile/Makefile b/drivers/gpu/drm/renesas/shmobile/Makefile index 861edafed8562..2679555d61a70 100644 --- a/drivers/gpu/drm/renesas/shmobile/Makefile +++ b/drivers/gpu/drm/renesas/shmobile/Makefile @@ -1,6 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -shmob-drm-y := shmob_drm_backlight.o \ - shmob_drm_crtc.o \ +shmob-drm-y := shmob_drm_crtc.o \ shmob_drm_drv.o \ shmob_drm_kms.o \ shmob_drm_plane.o diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_backlight.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_backlight.c deleted file mode 100644 index 794573badfe86..0000000000000 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_backlight.c +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * shmob_drm_backlight.c -- SH Mobile DRM Backlight - * - * Copyright (C) 2012 Renesas Electronics Corporation - * - * Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#include - -#include "shmob_drm_backlight.h" -#include "shmob_drm_crtc.h" -#include "shmob_drm_drv.h" - -static int shmob_drm_backlight_update(struct backlight_device *bdev) -{ - struct shmob_drm_connector *scon = bl_get_data(bdev); - struct shmob_drm_device *sdev = scon->connector.dev->dev_private; - const struct shmob_drm_backlight_data *bdata = &sdev->pdata->backlight; - int brightness = backlight_get_brightness(bdev); - - return bdata->set_brightness(brightness); -} - -static int shmob_drm_backlight_get_brightness(struct backlight_device *bdev) -{ - struct shmob_drm_connector *scon = bl_get_data(bdev); - struct shmob_drm_device *sdev = scon->connector.dev->dev_private; - const struct shmob_drm_backlight_data *bdata = &sdev->pdata->backlight; - - return bdata->get_brightness(); -} - -static const struct backlight_ops shmob_drm_backlight_ops = { - .options = BL_CORE_SUSPENDRESUME, - .update_status = shmob_drm_backlight_update, - .get_brightness = shmob_drm_backlight_get_brightness, -}; - -void shmob_drm_backlight_dpms(struct shmob_drm_connector *scon, int mode) -{ - if (scon->backlight == NULL) - return; - - scon->backlight->props.power = mode == DRM_MODE_DPMS_ON - ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; - backlight_update_status(scon->backlight); -} - -int shmob_drm_backlight_init(struct shmob_drm_connector *scon) -{ - struct shmob_drm_device *sdev = scon->connector.dev->dev_private; - const struct shmob_drm_backlight_data *bdata = &sdev->pdata->backlight; - struct drm_connector *connector = &scon->connector; - struct drm_device *dev = connector->dev; - struct backlight_device *backlight; - - if (!bdata->max_brightness) - return 0; - - backlight = backlight_device_register(bdata->name, dev->dev, scon, - &shmob_drm_backlight_ops, NULL); - if (IS_ERR(backlight)) { - dev_err(dev->dev, "unable to register backlight device: %ld\n", - PTR_ERR(backlight)); - return PTR_ERR(backlight); - } - - backlight->props.max_brightness = bdata->max_brightness; - backlight->props.brightness = bdata->max_brightness; - backlight->props.power = FB_BLANK_POWERDOWN; - backlight_update_status(backlight); - - scon->backlight = backlight; - return 0; -} - -void shmob_drm_backlight_exit(struct shmob_drm_connector *scon) -{ - backlight_device_unregister(scon->backlight); -} diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_backlight.h b/drivers/gpu/drm/renesas/shmobile/shmob_drm_backlight.h deleted file mode 100644 index d9abb7a60be5c..0000000000000 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_backlight.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * shmob_drm_backlight.h -- SH Mobile DRM Backlight - * - * Copyright (C) 2012 Renesas Electronics Corporation - * - * Laurent Pinchart (laurent.pinchart@ideasonboard.com) - */ - -#ifndef __SHMOB_DRM_BACKLIGHT_H__ -#define __SHMOB_DRM_BACKLIGHT_H__ - -struct shmob_drm_connector; - -void shmob_drm_backlight_dpms(struct shmob_drm_connector *scon, int mode); -int shmob_drm_backlight_init(struct shmob_drm_connector *scon); -void shmob_drm_backlight_exit(struct shmob_drm_connector *scon); - -#endif /* __SHMOB_DRM_BACKLIGHT_H__ */ diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c index 2cdf8f9b06e5f..db9d8d440144d 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c @@ -7,7 +7,6 @@ * Laurent Pinchart (laurent.pinchart@ideasonboard.com) */ -#include #include #include @@ -24,7 +23,6 @@ #include #include -#include "shmob_drm_backlight.h" #include "shmob_drm_crtc.h" #include "shmob_drm_drv.h" #include "shmob_drm_kms.h" @@ -487,21 +485,9 @@ int shmob_drm_crtc_create(struct shmob_drm_device *sdev) * Encoder */ -#define to_shmob_encoder(e) \ - container_of(e, struct shmob_drm_encoder, encoder) - static void shmob_drm_encoder_dpms(struct drm_encoder *encoder, int mode) { - struct shmob_drm_encoder *senc = to_shmob_encoder(encoder); - struct shmob_drm_device *sdev = encoder->dev->dev_private; - struct shmob_drm_connector *scon = &sdev->connector; - - if (senc->dpms == mode) - return; - - shmob_drm_backlight_dpms(scon, mode); - - senc->dpms = mode; + /* No-op, everything is handled in the CRTC code. */ } static bool shmob_drm_encoder_mode_fixup(struct drm_encoder *encoder, @@ -553,11 +539,9 @@ static const struct drm_encoder_helper_funcs encoder_helper_funcs = { int shmob_drm_encoder_create(struct shmob_drm_device *sdev) { - struct drm_encoder *encoder = &sdev->encoder.encoder; + struct drm_encoder *encoder = &sdev->encoder; int ret; - sdev->encoder.dpms = DRM_MODE_DPMS_OFF; - encoder->possible_crtcs = 1; ret = drm_simple_encoder_init(sdev->ddev, encoder, @@ -622,9 +606,6 @@ static const struct drm_connector_helper_funcs connector_helper_funcs = { static void shmob_drm_connector_destroy(struct drm_connector *connector) { - struct shmob_drm_connector *scon = to_shmob_connector(connector); - - shmob_drm_backlight_exit(scon); drm_connector_unregister(connector); drm_connector_cleanup(connector); } @@ -653,13 +634,9 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev, drm_connector_helper_add(connector, &connector_helper_funcs); - ret = shmob_drm_backlight_init(&sdev->connector); - if (ret < 0) - goto err_cleanup; - ret = drm_connector_attach_encoder(connector, encoder); if (ret < 0) - goto err_backlight; + goto error; drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); drm_object_property_set_value(&connector->base, @@ -667,9 +644,7 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev, return 0; -err_backlight: - shmob_drm_backlight_exit(&sdev->connector); -err_cleanup: +error: drm_connector_cleanup(connector); return ret; } diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.h b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.h index 21718843f46d3..bce6926269453 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.h +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.h @@ -14,7 +14,6 @@ #include #include -struct backlight_device; struct drm_pending_vblank_event; struct shmob_drm_device; struct shmob_drm_format_info; @@ -31,16 +30,9 @@ struct shmob_drm_crtc { bool started; }; -struct shmob_drm_encoder { - struct drm_encoder encoder; - int dpms; -}; - struct shmob_drm_connector { struct drm_connector connector; struct drm_encoder *encoder; - - struct backlight_device *backlight; }; int shmob_drm_crtc_create(struct shmob_drm_device *sdev); diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.h b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.h index 4964ddd5ab747..16d830168b2ad 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.h +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.h @@ -35,7 +35,7 @@ struct shmob_drm_device { struct drm_device *ddev; struct shmob_drm_crtc crtc; - struct shmob_drm_encoder encoder; + struct drm_encoder encoder; struct shmob_drm_connector connector; }; diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c index 8fd360149743f..3051318ddc799 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c @@ -159,7 +159,7 @@ int shmob_drm_modeset_init(struct shmob_drm_device *sdev) shmob_drm_crtc_create(sdev); shmob_drm_encoder_create(sdev); - shmob_drm_connector_create(sdev, &sdev->encoder.encoder); + shmob_drm_connector_create(sdev, &sdev->encoder); drm_kms_helper_poll_init(sdev->ddev); diff --git a/include/linux/platform_data/shmob_drm.h b/include/linux/platform_data/shmob_drm.h index d661399b217df..b6b5b6607fb5e 100644 --- a/include/linux/platform_data/shmob_drm.h +++ b/include/linux/platform_data/shmob_drm.h @@ -40,13 +40,6 @@ enum shmob_drm_interface { SHMOB_DRM_IFACE_SYS24, /* 24bpp */ }; -struct shmob_drm_backlight_data { - const char *name; - int max_brightness; - int (*get_brightness)(void); - int (*set_brightness)(int brightness); -}; - struct shmob_drm_panel_data { unsigned int width_mm; /* Panel width in mm */ unsigned int height_mm; /* Panel height in mm */ @@ -83,7 +76,6 @@ struct shmob_drm_platform_data { enum shmob_drm_clk_source clk_source; struct shmob_drm_interface_data iface; struct shmob_drm_panel_data panel; - struct shmob_drm_backlight_data backlight; }; #endif /* __SHMOB_DRM_H__ */ -- GitLab From 76b1405832ac067c16997fb7ede7b2e2517aa441 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 15 Sep 2023 10:53:28 +0200 Subject: [PATCH 0650/1451] drm: renesas: shmobile: Don't set display info width and height twice The display info width_mm and height_mm fields are set at init time and never overwritten, don't set them a second time when getting modes. Signed-off-by: Laurent Pinchart Reviewed-by: Sui Jingfeng Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/edd49fcb92af83d81df655b3db1685e8ed14380a.1694767209.git.geert+renesas@glider.be --- drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c index db9d8d440144d..2ccb2fbfea26b 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c @@ -585,9 +585,6 @@ static int shmob_drm_connector_get_modes(struct drm_connector *connector) drm_mode_set_name(mode); drm_mode_probed_add(connector, mode); - connector->display_info.width_mm = sdev->pdata->panel.width_mm; - connector->display_info.height_mm = sdev->pdata->panel.height_mm; - return 1; } -- GitLab From e2eb7e6ee5667f0b5b622020906446e3acbdd4b3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 15 Sep 2023 10:53:29 +0200 Subject: [PATCH 0651/1451] drm: renesas: shmobile: Rename input clocks Prepare for DT bindings by using more appropriate names for the input clocks. Note that all LDDCKR_ICKSEL_* definitions but the one for the bus clock are valid only for SH7724, so the clock selection code needs to be updated when extending clock support to other SoCs. Signed-off-by: Laurent Pinchart [geert: Add note] Reviewed-by: Sui Jingfeng Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/d4b4d2164541ae055d10064103db3c2d6540e846.1694767209.git.geert+renesas@glider.be --- drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c index 8a685bfc8e08e..5f3061e88e215 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c @@ -74,15 +74,15 @@ static int shmob_drm_setup_clocks(struct shmob_drm_device *sdev, switch (clksrc) { case SHMOB_DRM_CLK_BUS: - clkname = "bus_clk"; + clkname = "fck"; sdev->lddckr = LDDCKR_ICKSEL_BUS; break; case SHMOB_DRM_CLK_PERIPHERAL: - clkname = "peripheral_clk"; + clkname = "media"; sdev->lddckr = LDDCKR_ICKSEL_MIPI; break; case SHMOB_DRM_CLK_EXTERNAL: - clkname = NULL; + clkname = "lclk"; sdev->lddckr = LDDCKR_ICKSEL_HDMI; break; default: -- GitLab From 04ed052f3ab4b3c4c3e8451522ffaa84479bf0fb Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 15 Sep 2023 10:53:30 +0200 Subject: [PATCH 0652/1451] drm: renesas: shmobile: Remove support for SYS panels SYS panels are not used, and have no defined DT bindings. Remove their support to avoid impeding DT support. It can always be added back later. Signed-off-by: Laurent Pinchart Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/4ccca2a5ac05c73ea9fd6e44b8bc443fd9d14e0d.1694767209.git.geert+renesas@glider.be --- .../gpu/drm/renesas/shmobile/shmob_drm_crtc.c | 20 --------------- .../gpu/drm/renesas/shmobile/shmob_drm_drv.c | 11 -------- include/linux/platform_data/shmob_drm.h | 25 ------------------- 3 files changed, 56 deletions(-) diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c index 2ccb2fbfea26b..015263ac2100c 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c @@ -55,24 +55,6 @@ static void shmob_drm_crtc_setup_geometry(struct shmob_drm_crtc *scrtc) | ((idata->flags & SHMOB_DRM_IFACE_FL_DWCNT) ? LDMT1R_DWCNT : 0); lcdc_write(sdev, LDMT1R, value); - if (idata->interface >= SHMOB_DRM_IFACE_SYS8A && - idata->interface <= SHMOB_DRM_IFACE_SYS24) { - /* Setup SYS bus. */ - value = (idata->sys.cs_setup << LDMT2R_CSUP_SHIFT) - | (idata->sys.vsync_active_high ? LDMT2R_RSV : 0) - | (idata->sys.vsync_dir_input ? LDMT2R_VSEL : 0) - | (idata->sys.write_setup << LDMT2R_WCSC_SHIFT) - | (idata->sys.write_cycle << LDMT2R_WCEC_SHIFT) - | (idata->sys.write_strobe << LDMT2R_WCLW_SHIFT); - lcdc_write(sdev, LDMT2R, value); - - value = (idata->sys.read_latch << LDMT3R_RDLC_SHIFT) - | (idata->sys.read_setup << LDMT3R_RCSC_SHIFT) - | (idata->sys.read_cycle << LDMT3R_RCEC_SHIFT) - | (idata->sys.read_strobe << LDMT3R_RCLW_SHIFT); - lcdc_write(sdev, LDMT3R, value); - } - value = ((mode->hdisplay / 8) << 16) /* HDCN */ | (mode->htotal / 8); /* HTCN */ lcdc_write(sdev, LDHCNR, value); @@ -180,8 +162,6 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc) lcdc_write(sdev, LDDCKSTPR, 0); lcdc_wait_bit(sdev, LDDCKSTPR, ~0, 0); - /* TODO: Setup SYS panel */ - /* Setup geometry, format, frame buffer memory and operation mode. */ shmob_drm_crtc_setup_geometry(scrtc); diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c index 5f3061e88e215..9c3d8b3cf57d5 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c @@ -43,17 +43,6 @@ static int shmob_drm_init_interface(struct shmob_drm_device *sdev) [SHMOB_DRM_IFACE_RGB18] = LDMT1R_MIFTYP_RGB18, [SHMOB_DRM_IFACE_RGB24] = LDMT1R_MIFTYP_RGB24, [SHMOB_DRM_IFACE_YUV422] = LDMT1R_MIFTYP_YCBCR, - [SHMOB_DRM_IFACE_SYS8A] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8A, - [SHMOB_DRM_IFACE_SYS8B] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8B, - [SHMOB_DRM_IFACE_SYS8C] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8C, - [SHMOB_DRM_IFACE_SYS8D] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS8D, - [SHMOB_DRM_IFACE_SYS9] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS9, - [SHMOB_DRM_IFACE_SYS12] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS12, - [SHMOB_DRM_IFACE_SYS16A] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16A, - [SHMOB_DRM_IFACE_SYS16B] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16B, - [SHMOB_DRM_IFACE_SYS16C] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS16C, - [SHMOB_DRM_IFACE_SYS18] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS18, - [SHMOB_DRM_IFACE_SYS24] = LDMT1R_IFM | LDMT1R_MIFTYP_SYS24, }; if (sdev->pdata->iface.interface >= ARRAY_SIZE(ldmt1r)) { diff --git a/include/linux/platform_data/shmob_drm.h b/include/linux/platform_data/shmob_drm.h index b6b5b6607fb5e..b728e24222d99 100644 --- a/include/linux/platform_data/shmob_drm.h +++ b/include/linux/platform_data/shmob_drm.h @@ -27,17 +27,6 @@ enum shmob_drm_interface { SHMOB_DRM_IFACE_RGB18, /* 18bpp */ SHMOB_DRM_IFACE_RGB24, /* 24bpp */ SHMOB_DRM_IFACE_YUV422, /* 16bpp */ - SHMOB_DRM_IFACE_SYS8A, /* 24bpp, 8:8:8 */ - SHMOB_DRM_IFACE_SYS8B, /* 18bpp, 8:8:2 */ - SHMOB_DRM_IFACE_SYS8C, /* 18bpp, 2:8:8 */ - SHMOB_DRM_IFACE_SYS8D, /* 16bpp, 8:8 */ - SHMOB_DRM_IFACE_SYS9, /* 18bpp, 9:9 */ - SHMOB_DRM_IFACE_SYS12, /* 24bpp, 12:12 */ - SHMOB_DRM_IFACE_SYS16A, /* 16bpp */ - SHMOB_DRM_IFACE_SYS16B, /* 18bpp, 16:2 */ - SHMOB_DRM_IFACE_SYS16C, /* 18bpp, 2:16 */ - SHMOB_DRM_IFACE_SYS18, /* 18bpp */ - SHMOB_DRM_IFACE_SYS24, /* 24bpp */ }; struct shmob_drm_panel_data { @@ -46,19 +35,6 @@ struct shmob_drm_panel_data { struct drm_mode_modeinfo mode; }; -struct shmob_drm_sys_interface_data { - unsigned int read_latch:6; - unsigned int read_setup:8; - unsigned int read_cycle:8; - unsigned int read_strobe:8; - unsigned int write_setup:8; - unsigned int write_cycle:8; - unsigned int write_strobe:8; - unsigned int cs_setup:3; - unsigned int vsync_active_high:1; - unsigned int vsync_dir_input:1; -}; - #define SHMOB_DRM_IFACE_FL_DWPOL (1 << 0) /* Rising edge dot clock data latch */ #define SHMOB_DRM_IFACE_FL_DIPOL (1 << 1) /* Active low display enable */ #define SHMOB_DRM_IFACE_FL_DAPOL (1 << 2) /* Active low display data */ @@ -67,7 +43,6 @@ struct shmob_drm_sys_interface_data { struct shmob_drm_interface_data { enum shmob_drm_interface interface; - struct shmob_drm_sys_interface_data sys; unsigned int clk_div; unsigned int flags; }; -- GitLab From 95478b0828752d5b91fe5a94f44d5713e4980599 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Sep 2023 10:53:31 +0200 Subject: [PATCH 0653/1451] drm: renesas: shmobile: Improve error handling Prepare for DT conversion, where panel probe can be deferred, by streamlining error propagation and handling: - Use dev_err_probe() to avoid printing error messages in case of probe deferral, - Propagate errors where needed. Reviewed-by: Laurent Pinchart Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/6dfac76e5b1c7dda3f96801ce83845a4235e2ccd.1694767209.git.geert+renesas@glider.be --- drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c | 3 ++- drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c | 14 +++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c index 9c3d8b3cf57d5..399fedd42271c 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c @@ -253,7 +253,8 @@ static int shmob_drm_probe(struct platform_device *pdev) ret = shmob_drm_modeset_init(sdev); if (ret < 0) { - dev_err(&pdev->dev, "failed to initialize mode setting\n"); + dev_err_probe(&pdev->dev, ret, + "failed to initialize mode setting\n"); goto err_free_drm_dev; } diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c index 3051318ddc799..1a62e7f8a8a9e 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c @@ -157,9 +157,17 @@ int shmob_drm_modeset_init(struct shmob_drm_device *sdev) if (ret) return ret; - shmob_drm_crtc_create(sdev); - shmob_drm_encoder_create(sdev); - shmob_drm_connector_create(sdev, &sdev->encoder); + ret = shmob_drm_crtc_create(sdev); + if (ret < 0) + return ret; + + ret = shmob_drm_encoder_create(sdev); + if (ret < 0) + return ret; + + ret = shmob_drm_connector_create(sdev, &sdev->encoder); + if (ret < 0) + return ret; drm_kms_helper_poll_init(sdev->ddev); -- GitLab From 901500a8ba5c8cf04f8ddc71d6d5c0b02a2c5cf1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Sep 2023 10:53:32 +0200 Subject: [PATCH 0654/1451] drm: renesas: shmobile: Convert to use devm_request_irq() Convert to managed IRQ handling, to simplify cleanup. Reviewed-by: Laurent Pinchart Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/8d870bdc59dd5e2754542388a03095ea09c96297.1694767209.git.geert+renesas@glider.be --- drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c index 399fedd42271c..bf3a9c1db1770 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c @@ -196,7 +196,6 @@ static void shmob_drm_remove(struct platform_device *pdev) drm_dev_unregister(ddev); drm_kms_helper_poll_fini(ddev); - free_irq(sdev->irq, ddev); drm_dev_put(ddev); } @@ -277,8 +276,8 @@ static int shmob_drm_probe(struct platform_device *pdev) goto err_modeset_cleanup; sdev->irq = ret; - ret = request_irq(sdev->irq, shmob_drm_irq, 0, ddev->driver->name, - ddev); + ret = devm_request_irq(&pdev->dev, sdev->irq, shmob_drm_irq, 0, + ddev->driver->name, ddev); if (ret < 0) { dev_err(&pdev->dev, "failed to install IRQ handler\n"); goto err_modeset_cleanup; @@ -290,14 +289,12 @@ static int shmob_drm_probe(struct platform_device *pdev) */ ret = drm_dev_register(ddev, 0); if (ret < 0) - goto err_irq_uninstall; + goto err_modeset_cleanup; drm_fbdev_generic_setup(ddev, 16); return 0; -err_irq_uninstall: - free_irq(sdev->irq, ddev); err_modeset_cleanup: drm_kms_helper_poll_fini(ddev); err_free_drm_dev: -- GitLab From 33505f7718186fbe74604c7217143a0845eaeb5f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Sep 2023 10:53:33 +0200 Subject: [PATCH 0655/1451] drm: renesas: shmobile: Remove custom plane destroy callback There is no need to call drm_plane_force_disable() from the plane's .destroy() callback, as the plane should have been disabled already before. See also commit 3c858a33858baa8c ("drm/plane_helper: don't disable plane in destroy function") for the generic plane helper case. After removing this call, shmob_drm_plane_destroy() becomes a simple wrapper around shmob_drm_plane_destroy(), hence replace it by the latter. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/8d7a3f250612085fdf4e06d377843e8f874b22d9.1694767209.git.geert+renesas@glider.be --- drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c index 0b2ab153e9ae7..3a5db319bad14 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c @@ -176,16 +176,10 @@ static int shmob_drm_plane_disable(struct drm_plane *plane, return 0; } -static void shmob_drm_plane_destroy(struct drm_plane *plane) -{ - drm_plane_force_disable(plane); - drm_plane_cleanup(plane); -} - static const struct drm_plane_funcs shmob_drm_plane_funcs = { .update_plane = shmob_drm_plane_update, .disable_plane = shmob_drm_plane_disable, - .destroy = shmob_drm_plane_destroy, + .destroy = drm_plane_cleanup, }; static const uint32_t formats[] = { -- GitLab From 3d77d2ac7d9d5218a1f3df49e5bf8bd5c4f35b5a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Sep 2023 10:53:34 +0200 Subject: [PATCH 0656/1451] drm: renesas: shmobile: Use drmm_universal_plane_alloc() According to the comments for drm_universal_plane_init(), the plane structure should not be allocated with devm_kzalloc(). Fix lifetime issues by using drmm_universal_plane_alloc() instead. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/65ebf0513e2836227a9636e922f51c668bd69720.1694767209.git.geert+renesas@glider.be --- .../gpu/drm/renesas/shmobile/shmob_drm_plane.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c index 3a5db319bad14..1fb68b5fe915b 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c @@ -179,7 +179,6 @@ static int shmob_drm_plane_disable(struct drm_plane *plane, static const struct drm_plane_funcs shmob_drm_plane_funcs = { .update_plane = shmob_drm_plane_update, .disable_plane = shmob_drm_plane_disable, - .destroy = drm_plane_cleanup, }; static const uint32_t formats[] = { @@ -198,19 +197,16 @@ static const uint32_t formats[] = { int shmob_drm_plane_create(struct shmob_drm_device *sdev, unsigned int index) { struct shmob_drm_plane *splane; - int ret; - splane = devm_kzalloc(sdev->dev, sizeof(*splane), GFP_KERNEL); - if (splane == NULL) - return -ENOMEM; + splane = drmm_universal_plane_alloc(sdev->ddev, struct shmob_drm_plane, + plane, 1, &shmob_drm_plane_funcs, + formats, ARRAY_SIZE(formats), NULL, + DRM_PLANE_TYPE_OVERLAY, NULL); + if (IS_ERR(splane)) + return PTR_ERR(splane); splane->index = index; splane->alpha = 255; - ret = drm_universal_plane_init(sdev->ddev, &splane->plane, 1, - &shmob_drm_plane_funcs, - formats, ARRAY_SIZE(formats), NULL, - DRM_PLANE_TYPE_OVERLAY, NULL); - - return ret; + return 0; } -- GitLab From 5417750d5ee645eb4169e1e8dc467b0b7b7329fa Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Sep 2023 10:53:35 +0200 Subject: [PATCH 0657/1451] drm: renesas: shmobile: Embed drm_device in shmob_drm_device Embedding drm_device in shmob_drm_device allows us to use the DRM managed API to allocate both structures in one go, simplifying error handling. Reviewed-by: Laurent Pinchart Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/abbf95021191824f44cc8c52e4afbde93d44363a.1694767209.git.geert+renesas@glider.be --- .../gpu/drm/renesas/shmobile/shmob_drm_crtc.c | 12 +++--- .../gpu/drm/renesas/shmobile/shmob_drm_drv.c | 40 +++++++------------ .../gpu/drm/renesas/shmobile/shmob_drm_drv.h | 2 +- .../gpu/drm/renesas/shmobile/shmob_drm_kms.c | 16 ++++---- .../drm/renesas/shmobile/shmob_drm_plane.c | 8 ++-- 5 files changed, 34 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c index 015263ac2100c..9c66e00ed70ea 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c @@ -116,7 +116,7 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc) struct shmob_drm_device *sdev = crtc->dev->dev_private; const struct shmob_drm_interface_data *idata = &sdev->pdata->iface; const struct shmob_drm_format_info *format; - struct drm_device *dev = sdev->ddev; + struct drm_device *dev = &sdev->ddev; struct drm_plane *plane; u32 value; int ret; @@ -439,7 +439,7 @@ int shmob_drm_crtc_create(struct shmob_drm_device *sdev) sdev->crtc.dpms = DRM_MODE_DPMS_OFF; - primary = __drm_universal_plane_alloc(sdev->ddev, sizeof(*primary), 0, + primary = __drm_universal_plane_alloc(&sdev->ddev, sizeof(*primary), 0, 0, &primary_plane_funcs, modeset_formats, ARRAY_SIZE(modeset_formats), @@ -448,7 +448,7 @@ int shmob_drm_crtc_create(struct shmob_drm_device *sdev) if (IS_ERR(primary)) return PTR_ERR(primary); - ret = drm_crtc_init_with_planes(sdev->ddev, crtc, primary, NULL, + ret = drm_crtc_init_with_planes(&sdev->ddev, crtc, primary, NULL, &crtc_funcs, NULL); if (ret < 0) { drm_plane_cleanup(primary); @@ -524,7 +524,7 @@ int shmob_drm_encoder_create(struct shmob_drm_device *sdev) encoder->possible_crtcs = 1; - ret = drm_simple_encoder_init(sdev->ddev, encoder, + ret = drm_simple_encoder_init(&sdev->ddev, encoder, DRM_MODE_ENCODER_DPI); if (ret < 0) return ret; @@ -604,7 +604,7 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev, connector->display_info.width_mm = sdev->pdata->panel.width_mm; connector->display_info.height_mm = sdev->pdata->panel.height_mm; - ret = drm_connector_init(sdev->ddev, connector, &connector_funcs, + ret = drm_connector_init(&sdev->ddev, connector, &connector_funcs, DRM_MODE_CONNECTOR_DPI); if (ret < 0) return ret; @@ -617,7 +617,7 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev, drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); drm_object_property_set_value(&connector->base, - sdev->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF); + sdev->ddev.mode_config.dpms_property, DRM_MODE_DPMS_OFF); return 0; diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c index bf3a9c1db1770..56e2f407ab53a 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c @@ -137,7 +137,7 @@ static int shmob_drm_pm_suspend(struct device *dev) { struct shmob_drm_device *sdev = dev_get_drvdata(dev); - drm_kms_helper_poll_disable(sdev->ddev); + drm_kms_helper_poll_disable(&sdev->ddev); shmob_drm_crtc_suspend(&sdev->crtc); return 0; @@ -147,11 +147,11 @@ static int shmob_drm_pm_resume(struct device *dev) { struct shmob_drm_device *sdev = dev_get_drvdata(dev); - drm_modeset_lock_all(sdev->ddev); + drm_modeset_lock_all(&sdev->ddev); shmob_drm_crtc_resume(&sdev->crtc); - drm_modeset_unlock_all(sdev->ddev); + drm_modeset_unlock_all(&sdev->ddev); - drm_kms_helper_poll_enable(sdev->ddev); + drm_kms_helper_poll_enable(&sdev->ddev); return 0; } @@ -192,11 +192,10 @@ static const struct dev_pm_ops shmob_drm_pm_ops = { static void shmob_drm_remove(struct platform_device *pdev) { struct shmob_drm_device *sdev = platform_get_drvdata(pdev); - struct drm_device *ddev = sdev->ddev; + struct drm_device *ddev = &sdev->ddev; drm_dev_unregister(ddev); drm_kms_helper_poll_fini(ddev); - drm_dev_put(ddev); } static int shmob_drm_probe(struct platform_device *pdev) @@ -213,13 +212,15 @@ static int shmob_drm_probe(struct platform_device *pdev) } /* - * Allocate and initialize the driver private data, I/O resources and - * clocks. + * Allocate and initialize the DRM device, driver private data, I/O + * resources and clocks. */ - sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL); - if (sdev == NULL) - return -ENOMEM; + sdev = devm_drm_dev_alloc(&pdev->dev, &shmob_drm_driver, + struct shmob_drm_device, ddev); + if (IS_ERR(sdev)) + return PTR_ERR(sdev); + ddev = &sdev->ddev; sdev->dev = &pdev->dev; sdev->pdata = pdata; spin_lock_init(&sdev->irq_lock); @@ -242,20 +243,12 @@ static int shmob_drm_probe(struct platform_device *pdev) if (ret < 0) return ret; - /* Allocate and initialize the DRM device. */ - ddev = drm_dev_alloc(&shmob_drm_driver, &pdev->dev); - if (IS_ERR(ddev)) - return PTR_ERR(ddev); - - sdev->ddev = ddev; ddev->dev_private = sdev; ret = shmob_drm_modeset_init(sdev); - if (ret < 0) { - dev_err_probe(&pdev->dev, ret, - "failed to initialize mode setting\n"); - goto err_free_drm_dev; - } + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "failed to initialize mode setting\n"); for (i = 0; i < 4; ++i) { ret = shmob_drm_plane_create(sdev, i); @@ -297,9 +290,6 @@ static int shmob_drm_probe(struct platform_device *pdev) err_modeset_cleanup: drm_kms_helper_poll_fini(ddev); -err_free_drm_dev: - drm_dev_put(ddev); - return ret; } diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.h b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.h index 16d830168b2ad..77bb0da48f37a 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.h +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.h @@ -32,7 +32,7 @@ struct shmob_drm_device { unsigned int irq; spinlock_t irq_lock; /* Protects hardware LDINTR register */ - struct drm_device *ddev; + struct drm_device ddev; struct shmob_drm_crtc crtc; struct drm_encoder encoder; diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c index 1a62e7f8a8a9e..20316907030b2 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_kms.c @@ -153,7 +153,7 @@ int shmob_drm_modeset_init(struct shmob_drm_device *sdev) { int ret; - ret = drmm_mode_config_init(sdev->ddev); + ret = drmm_mode_config_init(&sdev->ddev); if (ret) return ret; @@ -169,15 +169,15 @@ int shmob_drm_modeset_init(struct shmob_drm_device *sdev) if (ret < 0) return ret; - drm_kms_helper_poll_init(sdev->ddev); + drm_kms_helper_poll_init(&sdev->ddev); - sdev->ddev->mode_config.min_width = 0; - sdev->ddev->mode_config.min_height = 0; - sdev->ddev->mode_config.max_width = 4095; - sdev->ddev->mode_config.max_height = 4095; - sdev->ddev->mode_config.funcs = &shmob_drm_mode_config_funcs; + sdev->ddev.mode_config.min_width = 0; + sdev->ddev.mode_config.min_height = 0; + sdev->ddev.mode_config.max_width = 4095; + sdev->ddev.mode_config.max_height = 4095; + sdev->ddev.mode_config.funcs = &shmob_drm_mode_config_funcs; - drm_helper_disable_unused_functions(sdev->ddev); + drm_helper_disable_unused_functions(&sdev->ddev); return 0; } diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c index 1fb68b5fe915b..17e66a018689f 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c @@ -68,7 +68,7 @@ static void __shmob_drm_plane_setup(struct shmob_drm_plane *splane, splane->format->ldbbsifr; #define plane_reg_dump(sdev, splane, reg) \ - dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x 0x%08x\n", __func__, \ + dev_dbg(sdev->ddev.dev, "%s(%u): %s 0x%08x 0x%08x\n", __func__, \ splane->index, #reg, \ lcdc_read(sdev, reg(splane->index)), \ lcdc_read(sdev, reg(splane->index) + LCDC_SIDE_B_OFFSET)) @@ -81,7 +81,7 @@ static void __shmob_drm_plane_setup(struct shmob_drm_plane *splane, plane_reg_dump(sdev, splane, LDBnBSACR); lcdc_write(sdev, LDBCR, LDBCR_UPC(splane->index)); - dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x\n", __func__, splane->index, + dev_dbg(sdev->ddev.dev, "%s(%u): %s 0x%08x\n", __func__, splane->index, "LDBCR", lcdc_read(sdev, LDBCR)); lcdc_write(sdev, LDBnBSIFR(splane->index), format); @@ -103,7 +103,7 @@ static void __shmob_drm_plane_setup(struct shmob_drm_plane *splane, lcdc_write(sdev, LDBCR, LDBCR_UPF(splane->index) | LDBCR_UPD(splane->index)); - dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x\n", __func__, splane->index, + dev_dbg(sdev->ddev.dev, "%s(%u): %s 0x%08x\n", __func__, splane->index, "LDBCR", lcdc_read(sdev, LDBCR)); plane_reg_dump(sdev, splane, LDBnBSIFR); @@ -198,7 +198,7 @@ int shmob_drm_plane_create(struct shmob_drm_device *sdev, unsigned int index) { struct shmob_drm_plane *splane; - splane = drmm_universal_plane_alloc(sdev->ddev, struct shmob_drm_plane, + splane = drmm_universal_plane_alloc(&sdev->ddev, struct shmob_drm_plane, plane, 1, &shmob_drm_plane_funcs, formats, ARRAY_SIZE(formats), NULL, DRM_PLANE_TYPE_OVERLAY, NULL); -- GitLab From 02e6c5b76f0eb6d85cebb7603c342809c3c6b14a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Sep 2023 10:53:36 +0200 Subject: [PATCH 0658/1451] drm: renesas: shmobile: Convert container helpers to static inline functions Replace to conversion helper macros using container_of() by static inline functions, to improve type-safety. Reviewed-by: Laurent Pinchart Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/7d1f1aa4b832499f9e527353ce0ad6d84ff9a74a.1694767209.git.geert+renesas@glider.be --- drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c | 11 ++++++++--- drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c | 5 ++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c index 9c66e00ed70ea..207fa98fe76d6 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c @@ -258,7 +258,10 @@ static void shmob_drm_crtc_update_base(struct shmob_drm_crtc *scrtc) lcdc_write(sdev, LDRCNTR, lcdc_read(sdev, LDRCNTR) ^ LDRCNTR_MRS); } -#define to_shmob_crtc(c) container_of(c, struct shmob_drm_crtc, crtc) +static inline struct shmob_drm_crtc *to_shmob_crtc(struct drm_crtc *crtc) +{ + return container_of(crtc, struct shmob_drm_crtc, crtc); +} static void shmob_drm_crtc_dpms(struct drm_crtc *crtc, int mode) { @@ -538,8 +541,10 @@ int shmob_drm_encoder_create(struct shmob_drm_device *sdev) * Connector */ -#define to_shmob_connector(c) \ - container_of(c, struct shmob_drm_connector, connector) +static inline struct shmob_drm_connector *to_shmob_connector(struct drm_connector *connector) +{ + return container_of(connector, struct shmob_drm_connector, connector); +} static int shmob_drm_connector_get_modes(struct drm_connector *connector) { diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c index 17e66a018689f..258288c80756b 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c @@ -34,7 +34,10 @@ struct shmob_drm_plane { unsigned int crtc_h; }; -#define to_shmob_plane(p) container_of(p, struct shmob_drm_plane, plane) +static inline struct shmob_drm_plane *to_shmob_plane(struct drm_plane *plane) +{ + return container_of(plane, struct shmob_drm_plane, plane); +} static void shmob_drm_plane_compute_base(struct shmob_drm_plane *splane, struct drm_framebuffer *fb, -- GitLab From c2e938ee9ae238f62424fc908cef97d96a1fee53 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Sep 2023 10:53:37 +0200 Subject: [PATCH 0659/1451] drm: renesas: shmobile: Replace .dev_private with container_of() Now that drm_device is embedded in shmob_drm_device, we can use a container_of()-based helper to get the shmob_drm_device pointer from the drm_device, instead of using the deprecated drm_device.dev_private field. While at it, restore reverse Xmas tree ordering of local variable declarations. Reviewed-by: Laurent Pinchart Reviewed-by: Sui Jingfeng Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/8ef4be8bffe75efc7f4b66f3732ec357f7d43e0f.1694767209.git.geert+renesas@glider.be --- .../gpu/drm/renesas/shmobile/shmob_drm_crtc.c | 20 +++++++++---------- .../gpu/drm/renesas/shmobile/shmob_drm_drv.c | 4 +--- .../gpu/drm/renesas/shmobile/shmob_drm_drv.h | 5 +++++ .../drm/renesas/shmobile/shmob_drm_plane.c | 6 +++--- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c index 207fa98fe76d6..f62ae047a48f6 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c @@ -40,7 +40,7 @@ static void shmob_drm_crtc_setup_geometry(struct shmob_drm_crtc *scrtc) { struct drm_crtc *crtc = &scrtc->crtc; - struct shmob_drm_device *sdev = crtc->dev->dev_private; + struct shmob_drm_device *sdev = to_shmob_device(crtc->dev); const struct shmob_drm_interface_data *idata = &sdev->pdata->iface; const struct drm_display_mode *mode = &crtc->mode; u32 value; @@ -79,7 +79,7 @@ static void shmob_drm_crtc_setup_geometry(struct shmob_drm_crtc *scrtc) static void shmob_drm_crtc_start_stop(struct shmob_drm_crtc *scrtc, bool start) { - struct shmob_drm_device *sdev = scrtc->crtc.dev->dev_private; + struct shmob_drm_device *sdev = to_shmob_device(scrtc->crtc.dev); u32 value; value = lcdc_read(sdev, LDCNT2R); @@ -113,7 +113,7 @@ static void shmob_drm_crtc_start_stop(struct shmob_drm_crtc *scrtc, bool start) static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc) { struct drm_crtc *crtc = &scrtc->crtc; - struct shmob_drm_device *sdev = crtc->dev->dev_private; + struct shmob_drm_device *sdev = to_shmob_device(crtc->dev); const struct shmob_drm_interface_data *idata = &sdev->pdata->iface; const struct shmob_drm_format_info *format; struct drm_device *dev = &sdev->ddev; @@ -193,7 +193,7 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc) static void shmob_drm_crtc_stop(struct shmob_drm_crtc *scrtc) { struct drm_crtc *crtc = &scrtc->crtc; - struct shmob_drm_device *sdev = crtc->dev->dev_private; + struct shmob_drm_device *sdev = to_shmob_device(crtc->dev); if (!scrtc->started) return; @@ -247,7 +247,7 @@ static void shmob_drm_crtc_compute_base(struct shmob_drm_crtc *scrtc, static void shmob_drm_crtc_update_base(struct shmob_drm_crtc *scrtc) { struct drm_crtc *crtc = &scrtc->crtc; - struct shmob_drm_device *sdev = crtc->dev->dev_private; + struct shmob_drm_device *sdev = to_shmob_device(crtc->dev); shmob_drm_crtc_compute_base(scrtc, crtc->x, crtc->y); @@ -289,8 +289,8 @@ static int shmob_drm_crtc_mode_set(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) { + struct shmob_drm_device *sdev = to_shmob_device(crtc->dev); struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc); - struct shmob_drm_device *sdev = crtc->dev->dev_private; const struct shmob_drm_format_info *format; format = shmob_drm_format_info(crtc->primary->fb->format->format); @@ -395,7 +395,7 @@ static void shmob_drm_crtc_enable_vblank(struct shmob_drm_device *sdev, static int shmob_drm_enable_vblank(struct drm_crtc *crtc) { - struct shmob_drm_device *sdev = crtc->dev->dev_private; + struct shmob_drm_device *sdev = to_shmob_device(crtc->dev); shmob_drm_crtc_enable_vblank(sdev, true); @@ -404,7 +404,7 @@ static int shmob_drm_enable_vblank(struct drm_crtc *crtc) static void shmob_drm_disable_vblank(struct drm_crtc *crtc) { - struct shmob_drm_device *sdev = crtc->dev->dev_private; + struct shmob_drm_device *sdev = to_shmob_device(crtc->dev); shmob_drm_crtc_enable_vblank(sdev, false); } @@ -478,7 +478,7 @@ static bool shmob_drm_encoder_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; - struct shmob_drm_device *sdev = dev->dev_private; + struct shmob_drm_device *sdev = to_shmob_device(dev); struct drm_connector *connector = &sdev->connector.connector; const struct drm_display_mode *panel_mode; @@ -548,7 +548,7 @@ static inline struct shmob_drm_connector *to_shmob_connector(struct drm_connecto static int shmob_drm_connector_get_modes(struct drm_connector *connector) { - struct shmob_drm_device *sdev = connector->dev->dev_private; + struct shmob_drm_device *sdev = to_shmob_device(connector->dev); struct drm_display_mode *mode; mode = drm_mode_create(connector->dev); diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c index 56e2f407ab53a..7e5977d3e256d 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.c @@ -95,7 +95,7 @@ static int shmob_drm_setup_clocks(struct shmob_drm_device *sdev, static irqreturn_t shmob_drm_irq(int irq, void *arg) { struct drm_device *dev = arg; - struct shmob_drm_device *sdev = dev->dev_private; + struct shmob_drm_device *sdev = to_shmob_device(dev); unsigned long flags; u32 status; @@ -243,8 +243,6 @@ static int shmob_drm_probe(struct platform_device *pdev) if (ret < 0) return ret; - ddev->dev_private = sdev; - ret = shmob_drm_modeset_init(sdev); if (ret < 0) return dev_err_probe(&pdev->dev, ret, diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.h b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.h index 77bb0da48f37a..5e55ba7a20786 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.h +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_drv.h @@ -39,4 +39,9 @@ struct shmob_drm_device { struct shmob_drm_connector connector; }; +static inline struct shmob_drm_device *to_shmob_device(struct drm_device *dev) +{ + return container_of(dev, struct shmob_drm_device, ddev); +} + #endif /* __SHMOB_DRM_DRV_H__ */ diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c index 258288c80756b..c58b9dca34736 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c @@ -63,7 +63,7 @@ static void shmob_drm_plane_compute_base(struct shmob_drm_plane *splane, static void __shmob_drm_plane_setup(struct shmob_drm_plane *splane, struct drm_framebuffer *fb) { - struct shmob_drm_device *sdev = splane->plane.dev->dev_private; + struct shmob_drm_device *sdev = to_shmob_device(splane->plane.dev); u32 format; /* TODO: Support ROP3 mode */ @@ -135,8 +135,8 @@ shmob_drm_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, uint32_t src_w, uint32_t src_h, struct drm_modeset_acquire_ctx *ctx) { + struct shmob_drm_device *sdev = to_shmob_device(plane->dev); struct shmob_drm_plane *splane = to_shmob_plane(plane); - struct shmob_drm_device *sdev = plane->dev->dev_private; const struct shmob_drm_format_info *format; format = shmob_drm_format_info(fb->format->format); @@ -167,8 +167,8 @@ shmob_drm_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, static int shmob_drm_plane_disable(struct drm_plane *plane, struct drm_modeset_acquire_ctx *ctx) { + struct shmob_drm_device *sdev = to_shmob_device(plane->dev); struct shmob_drm_plane *splane = to_shmob_plane(plane); - struct shmob_drm_device *sdev = plane->dev->dev_private; splane->format = NULL; -- GitLab From 6a6ab0c7162b4b10ce74347e282e1bc81103a48f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 15 Sep 2023 10:53:38 +0200 Subject: [PATCH 0660/1451] drm: renesas: shmobile: Use struct videomode in platform data Replace the drm_mode_modeinfo field with videomode that includes more signal polarity flags. This simplifies driver handling of panel modes and prepares for DT support. Signed-off-by: Laurent Pinchart [geert: Simplify] Reviewed-by: Laurent Pinchart Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/4312e56de424d94399c6105e7159317eae86c9d5.1694767209.git.geert+renesas@glider.be --- drivers/gpu/drm/renesas/shmobile/Kconfig | 1 + .../gpu/drm/renesas/shmobile/shmob_drm_crtc.c | 35 ++++++++----------- .../gpu/drm/renesas/shmobile/shmob_drm_crtc.h | 3 ++ include/linux/platform_data/shmob_drm.h | 11 ++---- 4 files changed, 20 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/renesas/shmobile/Kconfig b/drivers/gpu/drm/renesas/shmobile/Kconfig index ba941587ca70e..027220b8fe1c5 100644 --- a/drivers/gpu/drm/renesas/shmobile/Kconfig +++ b/drivers/gpu/drm/renesas/shmobile/Kconfig @@ -6,6 +6,7 @@ config DRM_SHMOBILE select BACKLIGHT_CLASS_DEVICE select DRM_KMS_HELPER select DRM_GEM_DMA_HELPER + select VIDEOMODE_HELPERS help Choose this option if you have an SH Mobile chipset. If M is selected the module will be called shmob-drm. diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c index f62ae047a48f6..b3ef10b7828de 100644 --- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_crtc.c @@ -23,6 +23,8 @@ #include #include +#include