* [PATCH v3 1/4] media: si2157: move firmware load to a separate function
2021-12-10 7:56 [PATCH v3 0/4] media: si2157: rework firmware load logic Mauro Carvalho Chehab
@ 2021-12-10 7:56 ` Mauro Carvalho Chehab
2021-12-10 7:56 ` [PATCH v3 2/4] media: si2157: Add optional firmware download Mauro Carvalho Chehab
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Mauro Carvalho Chehab @ 2021-12-10 7:56 UTC (permalink / raw)
Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Robert Schlabbach,
Antti Palosaari, Mauro Carvalho Chehab, linux-kernel,
linux-media
Split the firmware load code from si2157_init, in order to
help to add further changes at the way firmware is handled on
this device.
No functional changes.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
See [PATCH v3 0/4] at: https://lore.kernel.org/all/cover.1639120421.git.mchehab+huawei@kernel.org/
drivers/media/tuners/si2157.c | 98 ++++++++++++++++++++---------------
1 file changed, 56 insertions(+), 42 deletions(-)
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
index 75ddf7ed1faf..481a5db7fb69 100644
--- a/drivers/media/tuners/si2157.c
+++ b/drivers/media/tuners/si2157.c
@@ -76,16 +76,63 @@ static int si2157_cmd_execute(struct i2c_client *client, struct si2157_cmd *cmd)
return ret;
}
-static int si2157_init(struct dvb_frontend *fe)
+static int si2157_load_firmware(struct dvb_frontend *fe,
+ const char *fw_name)
{
struct i2c_client *client = fe->tuner_priv;
- struct si2157_dev *dev = i2c_get_clientdata(client);
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- int ret, len, remaining;
- struct si2157_cmd cmd;
const struct firmware *fw;
- const char *fw_name;
+ int ret, len, remaining;
+ struct si2157_cmd cmd;
+
+ /* request the firmware, this will block and timeout */
+ ret = request_firmware(&fw, fw_name, &client->dev);
+ if (ret)
+ return ret;
+
+ /* firmware should be n chunks of 17 bytes */
+ if (fw->size % 17 != 0) {
+ dev_err(&client->dev, "firmware file '%s' is invalid\n",
+ fw_name);
+ ret = -EINVAL;
+ goto err_release_firmware;
+ }
+
+ dev_info(&client->dev, "downloading firmware from file '%s'\n",
+ fw_name);
+
+ for (remaining = fw->size; remaining > 0; remaining -= 17) {
+ len = fw->data[fw->size - remaining];
+ if (len > SI2157_ARGLEN) {
+ dev_err(&client->dev, "Bad firmware length\n");
+ ret = -EINVAL;
+ goto err_release_firmware;
+ }
+ memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len);
+ cmd.wlen = len;
+ cmd.rlen = 1;
+ ret = si2157_cmd_execute(client, &cmd);
+ if (ret) {
+ dev_err(&client->dev, "firmware download failed %d\n",
+ ret);
+ goto err_release_firmware;
+ }
+ }
+
+err_release_firmware:
+ release_firmware(fw);
+
+ return ret;
+}
+
+static int si2157_init(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct i2c_client *client = fe->tuner_priv;
+ struct si2157_dev *dev = i2c_get_clientdata(client);
unsigned int chip_id, xtal_trim;
+ struct si2157_cmd cmd;
+ const char *fw_name;
+ int ret;
dev_dbg(&client->dev, "\n");
@@ -181,45 +228,13 @@ static int si2157_init(struct dvb_frontend *fe)
if (fw_name == NULL)
goto skip_fw_download;
- /* request the firmware, this will block and timeout */
- ret = request_firmware(&fw, fw_name, &client->dev);
+ ret = si2157_load_firmware(fe, fw_name);
if (ret) {
dev_err(&client->dev, "firmware file '%s' not found\n",
- fw_name);
- goto err;
- }
-
- /* firmware should be n chunks of 17 bytes */
- if (fw->size % 17 != 0) {
- dev_err(&client->dev, "firmware file '%s' is invalid\n",
- fw_name);
- ret = -EINVAL;
- goto err_release_firmware;
- }
-
- dev_info(&client->dev, "downloading firmware from file '%s'\n",
fw_name);
-
- for (remaining = fw->size; remaining > 0; remaining -= 17) {
- len = fw->data[fw->size - remaining];
- if (len > SI2157_ARGLEN) {
- dev_err(&client->dev, "Bad firmware length\n");
- ret = -EINVAL;
- goto err_release_firmware;
- }
- memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len);
- cmd.wlen = len;
- cmd.rlen = 1;
- ret = si2157_cmd_execute(client, &cmd);
- if (ret) {
- dev_err(&client->dev, "firmware download failed %d\n",
- ret);
- goto err_release_firmware;
- }
+ goto err;
}
- release_firmware(fw);
-
skip_fw_download:
/* reboot the tuner with new firmware? */
memcpy(cmd.args, "\x01\x01", 2);
@@ -270,8 +285,7 @@ static int si2157_init(struct dvb_frontend *fe)
dev->active = true;
return 0;
-err_release_firmware:
- release_firmware(fw);
+
err:
dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
--
2.33.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v3 3/4] media: si2157: rework the firmware load logic
2021-12-10 7:56 [PATCH v3 0/4] media: si2157: rework firmware load logic Mauro Carvalho Chehab
2021-12-10 7:56 ` [PATCH v3 1/4] media: si2157: move firmware load to a separate function Mauro Carvalho Chehab
2021-12-10 7:56 ` [PATCH v3 2/4] media: si2157: Add optional firmware download Mauro Carvalho Chehab
@ 2021-12-10 7:56 ` Mauro Carvalho Chehab
2021-12-10 7:56 ` [PATCH v3 4/4] media: si2157: use a different namespace for firmware Mauro Carvalho Chehab
3 siblings, 0 replies; 5+ messages in thread
From: Mauro Carvalho Chehab @ 2021-12-10 7:56 UTC (permalink / raw)
Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Robert Schlabbach,
Antti Palosaari, Mauro Carvalho Chehab, linux-kernel,
linux-media
Loading a firmware file should not be mandatory, as devices
could work with an eeprom firmware, if available.
Yet, using the eeprom firmware could lead into unpredictable
results, so the best is to warn about that.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
See [PATCH v3 0/4] at: https://lore.kernel.org/all/cover.1639120421.git.mchehab+huawei@kernel.org/
drivers/media/tuners/si2157.c | 31 ++++++++++++++++++-------------
1 file changed, 18 insertions(+), 13 deletions(-)
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
index ed28672c060d..5f4ae8593864 100644
--- a/drivers/media/tuners/si2157.c
+++ b/drivers/media/tuners/si2157.c
@@ -129,8 +129,9 @@ static int si2157_init(struct dvb_frontend *fe)
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct i2c_client *client = fe->tuner_priv;
struct si2157_dev *dev = i2c_get_clientdata(client);
+ bool warn_firmware_not_loaded = false;
unsigned int chip_id, xtal_trim;
- unsigned int fw_required;
+ bool fw_required = true;
struct si2157_cmd cmd;
const char *fw_name;
int ret;
@@ -199,10 +200,6 @@ static int si2157_init(struct dvb_frontend *fe)
#define SI2146_A10 ('A' << 24 | 46 << 16 | '1' << 8 | '0' << 0)
#define SI2141_A10 ('A' << 24 | 41 << 16 | '1' << 8 | '0' << 0)
- /* assume firmware is required, unless verified not to be */
- /* only the SI2157_A30 has been verified not to yet */
- fw_required = true;
-
switch (chip_id) {
case SI2158_A20:
case SI2148_A20:
@@ -212,9 +209,8 @@ static int si2157_init(struct dvb_frontend *fe)
fw_name = SI2141_A10_FIRMWARE;
break;
case SI2157_A30:
- fw_name = SI2157_A30_FIRMWARE;
fw_required = false;
- break;
+ fallthrough;
case SI2177_A30:
fw_name = SI2157_A30_FIRMWARE;
break;
@@ -237,12 +233,11 @@ static int si2157_init(struct dvb_frontend *fe)
goto skip_fw_download;
ret = si2157_load_firmware(fe, fw_name);
- if (ret) {
- if (!fw_required)
- goto skip_fw_download;
-
- dev_err(&client->dev, "firmware file '%s' not found\n",
- fw_name);
+ if (fw_required && ret == -ENOENT)
+ warn_firmware_not_loaded = true;
+ else if (ret < 0) {
+ dev_err(&client->dev, "error %d when loading firmware file '%s'\n",
+ ret, fw_name);
goto err;
}
@@ -263,6 +258,11 @@ static int si2157_init(struct dvb_frontend *fe)
if (ret)
goto err;
+ if (warn_firmware_not_loaded) {
+ dev_warn(&client->dev, "firmware file '%s' not found. Using firmware from eeprom.\n",
+ fw_name);
+ warn_firmware_not_loaded = false;
+ }
dev_info(&client->dev, "firmware version: %c.%c.%d\n",
cmd.args[6], cmd.args[7], cmd.args[8]);
@@ -298,6 +298,11 @@ static int si2157_init(struct dvb_frontend *fe)
return 0;
err:
+ if (warn_firmware_not_loaded)
+ dev_err(&client->dev,
+ "firmware file '%s' not found. Can't continue without a firmware.\n",
+ fw_name);
+
dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
--
2.33.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v3 4/4] media: si2157: use a different namespace for firmware
2021-12-10 7:56 [PATCH v3 0/4] media: si2157: rework firmware load logic Mauro Carvalho Chehab
` (2 preceding siblings ...)
2021-12-10 7:56 ` [PATCH v3 3/4] media: si2157: rework the firmware load logic Mauro Carvalho Chehab
@ 2021-12-10 7:56 ` Mauro Carvalho Chehab
3 siblings, 0 replies; 5+ messages in thread
From: Mauro Carvalho Chehab @ 2021-12-10 7:56 UTC (permalink / raw)
Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Robert Schlabbach,
Antti Palosaari, Mauro Carvalho Chehab, linux-kernel,
linux-media
Each chip at the si21xx TER family seems to have a different firmware,
with seems to actually be a patch against the ROM code.
Rework the code in order to use different firmware files depending
on the chip ID and rom ID.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
See [PATCH v3 0/4] at: https://lore.kernel.org/all/cover.1639120421.git.mchehab+huawei@kernel.org/
drivers/media/tuners/si2157.c | 180 ++++++++++++++++-------------
drivers/media/tuners/si2157_priv.h | 31 +++++
2 files changed, 132 insertions(+), 79 deletions(-)
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
index 5f4ae8593864..bb590395e81a 100644
--- a/drivers/media/tuners/si2157.c
+++ b/drivers/media/tuners/si2157.c
@@ -76,6 +76,19 @@ static int si2157_cmd_execute(struct i2c_client *client, struct si2157_cmd *cmd)
return ret;
}
+static const struct si2157_tuner_info si2157_tuners[] = {
+ { SI2141, false, 0x60, SI2141_60_FIRMWARE, SI2141_A10_FIRMWARE },
+ { SI2141, false, 0x61, SI2141_61_FIRMWARE, SI2141_A10_FIRMWARE },
+ { SI2146, false, 0x11, SI2146_11_FIRMWARE, NULL },
+ { SI2147, false, 0x50, SI2147_50_FIRMWARE, NULL },
+ { SI2148, true, 0x32, SI2148_32_FIRMWARE, SI2158_A20_FIRMWARE },
+ { SI2148, true, 0x33, SI2148_33_FIRMWARE, SI2158_A20_FIRMWARE },
+ { SI2157, false, 0x50, SI2157_50_FIRMWARE, SI2157_A30_FIRMWARE },
+ { SI2158, false, 0x50, SI2158_50_FIRMWARE, SI2158_A20_FIRMWARE },
+ { SI2158, false, 0x51, SI2158_51_FIRMWARE, SI2158_A20_FIRMWARE },
+ { SI2177, false, 0x50, SI2177_50_FIRMWARE, SI2157_A30_FIRMWARE },
+};
+
static int si2157_load_firmware(struct dvb_frontend *fe,
const char *fw_name)
{
@@ -85,7 +98,7 @@ static int si2157_load_firmware(struct dvb_frontend *fe,
struct si2157_cmd cmd;
/* request the firmware, this will block and timeout */
- ret = request_firmware(&fw, fw_name, &client->dev);
+ ret = firmware_request_nowarn(&fw, fw_name, &client->dev);
if (ret)
return ret;
@@ -124,16 +137,86 @@ static int si2157_load_firmware(struct dvb_frontend *fe,
return ret;
}
+static int si2157_find_and_load_firmware(struct dvb_frontend *fe)
+{
+ struct i2c_client *client = fe->tuner_priv;
+ struct si2157_dev *dev = i2c_get_clientdata(client);
+ const char *fw_alt_name = NULL;
+ unsigned char part_id, rom_id;
+ const char *fw_name = NULL;
+ struct si2157_cmd cmd;
+ bool required = true;
+ int ret, i;
+
+ if (dev->dont_load_firmware) {
+ dev_info(&client->dev,
+ "device is buggy, skipping firmware download\n");
+ return 0;
+ }
+
+ /* query chip revision */
+ memcpy(cmd.args, "\x02", 1);
+ cmd.wlen = 1;
+ cmd.rlen = 13;
+ ret = si2157_cmd_execute(client, &cmd);
+ if (ret)
+ return ret;
+
+ part_id = cmd.args[2];
+ rom_id = cmd.args[12];
+
+ for (i = 0; i < ARRAY_SIZE(si2157_tuners); i++) {
+ if (si2157_tuners[i].part_id != part_id)
+ continue;
+ required = si2157_tuners[i].required;
+ fw_alt_name = si2157_tuners[i].fw_alt_name;
+
+ /* Both part and rom ID match */
+ if (si2157_tuners[i].rom_id == rom_id) {
+ fw_name = si2157_tuners[i].fw_name;
+ break;
+ }
+ }
+
+ if (!fw_name && !fw_alt_name) {
+ dev_err(&client->dev,
+ "unknown chip version Si21%d-%c%c%c ROM 0x%02x\n",
+ part_id, cmd.args[1], cmd.args[3], cmd.args[4], rom_id);
+ return -EINVAL;
+ }
+
+ dev_info(&client->dev,
+ "found a 'Silicon Labs Si21%d-%c%c%c ROM 0x%02x'\n",
+ part_id, cmd.args[1], cmd.args[3], cmd.args[4], rom_id);
+
+ if (fw_name)
+ ret = si2157_load_firmware(fe, fw_name);
+ else
+ ret = -ENOENT;
+
+ /* Try alternate name, if any */
+ if (ret == -ENOENT && fw_alt_name)
+ ret = si2157_load_firmware(fe, fw_alt_name);
+
+ if (ret == -ENOENT) {
+ if (!required) {
+ dev_info(&client->dev, "Using ROM firmware.\n");
+ return 0;
+ }
+ dev_err(&client->dev, "Can't continue without a firmware.\n");
+ } else if (ret < 0) {
+ dev_err(&client->dev, "error %d when loading firmware\n", ret);
+ }
+ return ret;
+}
+
static int si2157_init(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct i2c_client *client = fe->tuner_priv;
struct si2157_dev *dev = i2c_get_clientdata(client);
- bool warn_firmware_not_loaded = false;
- unsigned int chip_id, xtal_trim;
- bool fw_required = true;
+ unsigned int xtal_trim;
struct si2157_cmd cmd;
- const char *fw_name;
int ret;
dev_dbg(&client->dev, "\n");
@@ -176,72 +259,11 @@ static int si2157_init(struct dvb_frontend *fe)
goto err;
}
- if (dev->dont_load_firmware) {
- dev_info(&client->dev, "device is buggy, skipping firmware download\n");
- goto skip_fw_download;
- }
-
- /* query chip revision */
- memcpy(cmd.args, "\x02", 1);
- cmd.wlen = 1;
- cmd.rlen = 13;
- ret = si2157_cmd_execute(client, &cmd);
- if (ret)
- goto err;
-
- chip_id = cmd.args[1] << 24 | cmd.args[2] << 16 | cmd.args[3] << 8 |
- cmd.args[4] << 0;
-
- #define SI2177_A30 ('A' << 24 | 77 << 16 | '3' << 8 | '0' << 0)
- #define SI2158_A20 ('A' << 24 | 58 << 16 | '2' << 8 | '0' << 0)
- #define SI2148_A20 ('A' << 24 | 48 << 16 | '2' << 8 | '0' << 0)
- #define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0)
- #define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0)
- #define SI2146_A10 ('A' << 24 | 46 << 16 | '1' << 8 | '0' << 0)
- #define SI2141_A10 ('A' << 24 | 41 << 16 | '1' << 8 | '0' << 0)
-
- switch (chip_id) {
- case SI2158_A20:
- case SI2148_A20:
- fw_name = SI2158_A20_FIRMWARE;
- break;
- case SI2141_A10:
- fw_name = SI2141_A10_FIRMWARE;
- break;
- case SI2157_A30:
- fw_required = false;
- fallthrough;
- case SI2177_A30:
- fw_name = SI2157_A30_FIRMWARE;
- break;
- case SI2147_A30:
- case SI2146_A10:
- fw_name = NULL;
- break;
- default:
- dev_err(&client->dev, "unknown chip version Si21%d-%c%c%c\n",
- cmd.args[2], cmd.args[1],
- cmd.args[3], cmd.args[4]);
- ret = -EINVAL;
- goto err;
- }
-
- dev_info(&client->dev, "found a 'Silicon Labs Si21%d-%c%c%c'\n",
- cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]);
-
- if (fw_name == NULL)
- goto skip_fw_download;
-
- ret = si2157_load_firmware(fe, fw_name);
- if (fw_required && ret == -ENOENT)
- warn_firmware_not_loaded = true;
- else if (ret < 0) {
- dev_err(&client->dev, "error %d when loading firmware file '%s'\n",
- ret, fw_name);
+ /* Try to load the firmware */
+ ret = si2157_find_and_load_firmware(fe);
+ if (ret < 0)
goto err;
- }
-skip_fw_download:
/* reboot the tuner with new firmware? */
memcpy(cmd.args, "\x01\x01", 2);
cmd.wlen = 2;
@@ -258,11 +280,6 @@ static int si2157_init(struct dvb_frontend *fe)
if (ret)
goto err;
- if (warn_firmware_not_loaded) {
- dev_warn(&client->dev, "firmware file '%s' not found. Using firmware from eeprom.\n",
- fw_name);
- warn_firmware_not_loaded = false;
- }
dev_info(&client->dev, "firmware version: %c.%c.%d\n",
cmd.args[6], cmd.args[7], cmd.args[8]);
@@ -298,11 +315,6 @@ static int si2157_init(struct dvb_frontend *fe)
return 0;
err:
- if (warn_firmware_not_loaded)
- dev_err(&client->dev,
- "firmware file '%s' not found. Can't continue without a firmware.\n",
- fw_name);
-
dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
@@ -968,3 +980,13 @@ MODULE_LICENSE("GPL");
MODULE_FIRMWARE(SI2158_A20_FIRMWARE);
MODULE_FIRMWARE(SI2141_A10_FIRMWARE);
MODULE_FIRMWARE(SI2157_A30_FIRMWARE);
+MODULE_FIRMWARE(SI2141_60_FIRMWARE);
+MODULE_FIRMWARE(SI2141_61_FIRMWARE);
+MODULE_FIRMWARE(SI2146_11_FIRMWARE);
+MODULE_FIRMWARE(SI2147_50_FIRMWARE);
+MODULE_FIRMWARE(SI2148_32_FIRMWARE);
+MODULE_FIRMWARE(SI2148_33_FIRMWARE);
+MODULE_FIRMWARE(SI2157_50_FIRMWARE);
+MODULE_FIRMWARE(SI2158_50_FIRMWARE);
+MODULE_FIRMWARE(SI2158_51_FIRMWARE);
+MODULE_FIRMWARE(SI2177_50_FIRMWARE);
diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h
index ef4796098931..0db21b082ba9 100644
--- a/drivers/media/tuners/si2157_priv.h
+++ b/drivers/media/tuners/si2157_priv.h
@@ -41,6 +41,23 @@ struct si2157_dev {
};
+enum si2157_part_id {
+ SI2141 = 41,
+ SI2146 = 46,
+ SI2147 = 47,
+ SI2148 = 48,
+ SI2157 = 57,
+ SI2158 = 58,
+ SI2177 = 77,
+};
+
+struct si2157_tuner_info {
+ enum si2157_part_id part_id;
+ unsigned char rom_id;
+ bool required;
+ const char *fw_name, *fw_alt_name;
+};
+
#define SI2157_CHIPTYPE_SI2157 0
#define SI2157_CHIPTYPE_SI2146 1
#define SI2157_CHIPTYPE_SI2141 2
@@ -54,7 +71,21 @@ struct si2157_cmd {
unsigned rlen;
};
+/* Old firmware namespace */
#define SI2158_A20_FIRMWARE "dvb-tuner-si2158-a20-01.fw"
#define SI2141_A10_FIRMWARE "dvb-tuner-si2141-a10-01.fw"
#define SI2157_A30_FIRMWARE "dvb-tuner-si2157-a30-01.fw"
+
+/* New firmware namespace */
+#define SI2141_60_FIRMWARE "dvb_driver_si2141_rom60.fw"
+#define SI2141_61_FIRMWARE "dvb_driver_si2141_rom61.fw"
+#define SI2146_11_FIRMWARE "dvb_driver_si2146_rom11.fw"
+#define SI2147_50_FIRMWARE "dvb_driver_si2147_rom50.fw"
+#define SI2148_32_FIRMWARE "dvb_driver_si2148_rom32.fw"
+#define SI2148_33_FIRMWARE "dvb_driver_si2148_rom33.fw"
+#define SI2157_50_FIRMWARE "dvb_driver_si2157_rom50.fw"
+#define SI2158_50_FIRMWARE "dvb_driver_si2178_rom50.fw"
+#define SI2158_51_FIRMWARE "dvb_driver_si2158_rom51.fw"
+#define SI2177_50_FIRMWARE "dvb_driver_si2177_rom50.fw"
+
#endif
--
2.33.1
^ permalink raw reply related [flat|nested] 5+ messages in thread