soc/tegra: fuse: Add custom SoC attributes
Jon Hunter
maintainerPATCH v2 1/3 soc/tegra: fuse: Add custom SoC attributes
Add a custom SoC attribute for Tegra to expose the HIDREV register fields to userspace via the sysfs. This register provides additional details about the type of device (eg, silicon, FPGA, etc) as well as revision. Exposing this information is useful for identifying the exact device revision and device type.
For Tegra devices up until Tegra186, the majorrev and minorrev fields of the HIDREV register are used to determine the device revision and device type. For Tegra194, the majorrev and minorrev fields only determine the revision. Starting with Tegra194, there is an additional field, pre_si_platform (which occupies bits 20-23), that now determines device type. Therefore, for all Tegra devices, add a custom SoC attribute for the majorrev and minorrev fields and for Tegra194 add an additional attribute for the pre_si_platform field.
--- drivers/soc/tegra/fuse/fuse-tegra.c | 51 ++++++++++++++++++++++++++ drivers/soc/tegra/fuse/fuse-tegra20.c | 1 + drivers/soc/tegra/fuse/fuse-tegra30.c | 6 +++ drivers/soc/tegra/fuse/fuse.h | 8 ++++ drivers/soc/tegra/fuse/tegra-apbmisc.c | 10 +++++ 5 files changed, 76 insertions(+)
drivers/soc/tegra/fuse/fuse-tegra.c +51 -0
@@ -300,6 +300,56 @@ static void tegra_enable_fuse_clk(void __iomem *base)writel (reg, base +0x14 ); } +static ssize_t tegra_soc_majorrev_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +return sprintf (buf,"%d\n" ,tegra_get_major_rev ()); +} + +static DEVICE_ATTR(majorrev, S_IRUGO, tegra_soc_majorrev_show, NULL); + +static ssize_t tegra_soc_minorrev_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +return sprintf (buf,"%d\n" ,tegra_get_minor_rev ()); +} + +static DEVICE_ATTR(minorrev, S_IRUGO, tegra_soc_minorrev_show, NULL); + +static struct attribute *tegra_soc_attr[] = { + &dev_attr_majorrev.attr, + &dev_attr_minorrev.attr, +NULL , +}; + +const struct attribute_group tegra_soc_attr_group = { + .attrs = tegra_soc_attr, +}; + +#ifdef CONFIG_ARCH_TEGRA_194_SOC +static ssize_t tegra_soc_pre_si_plat_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +return sprintf (buf,"%d\n" , (tegra_read_chipid () >>20 ) &0xf ); +} + +static DEVICE_ATTR(pre_si_platform, S_IRUGO, tegra_soc_pre_si_plat_show, NULL); + +static struct attribute *tegra194_soc_attr[] = { + &dev_attr_majorrev.attr, + &dev_attr_minorrev.attr, + &dev_attr_pre_si_platform.attr, +NULL , +}; + +const struct attribute_group tegra194_soc_attr_group = { + .attrs = tegra194_soc_attr, +}; +#endif +struct device *__init tegra_soc_device_register (void ) {struct soc_device_attribute *attr;
@@ -312,6 +362,7 @@ struct device * __init tegra_soc_device_register(void) attr->family =kasprintf (GFP_KERNEL ,"Tegra" ); attr->revision =kasprintf (GFP_KERNEL ,"%d" , tegra_sku_info.revision); attr->soc_id =kasprintf (GFP_KERNEL ,"%u" ,tegra_get_chip_id ()); + attr->custom_attr_group = fuse->soc->soc_attr_group; dev =soc_device_register (attr);if (IS_ERR (dev)) {
drivers/soc/tegra/fuse/fuse-tegra20.c +1 -0
@@ -164,4 +164,5 @@ const struct tegra_fuse_soc tegra20_fuse_soc = { .speedo_init = tegra20_init_speedo_data, .probe = tegra20_fuse_probe, .info = &tegra20_fuse_info, + .soc_attr_group = &tegra_soc_attr_group, };
drivers/soc/tegra/fuse/fuse-tegra30.c +6 -0
@@ -111,6 +111,7 @@ const struct tegra_fuse_soc tegra30_fuse_soc = { .init = tegra30_fuse_init, .speedo_init = tegra30_init_speedo_data, .info = &tegra30_fuse_info, + .soc_attr_group = &tegra_soc_attr_group, };#endif
@@ -125,6 +126,7 @@ const struct tegra_fuse_soc tegra114_fuse_soc = { .init = tegra30_fuse_init, .speedo_init = tegra114_init_speedo_data, .info = &tegra114_fuse_info, + .soc_attr_group = &tegra_soc_attr_group, };#endif
@@ -205,6 +207,7 @@ const struct tegra_fuse_soc tegra124_fuse_soc = { .info = &tegra124_fuse_info, .lookups = tegra124_fuse_lookups, .num_lookups = ARRAY_SIZE(tegra124_fuse_lookups), + .soc_attr_group = &tegra_soc_attr_group, };#endif
@@ -290,6 +293,7 @@ const struct tegra_fuse_soc tegra210_fuse_soc = { .info = &tegra210_fuse_info, .lookups = tegra210_fuse_lookups, .num_lookups = ARRAY_SIZE(tegra210_fuse_lookups), + .soc_attr_group = &tegra_soc_attr_group, };#endif
@@ -319,6 +323,7 @@ const struct tegra_fuse_soc tegra186_fuse_soc = { .info = &tegra186_fuse_info, .lookups = tegra186_fuse_lookups, .num_lookups = ARRAY_SIZE(tegra186_fuse_lookups), + .soc_attr_group = &tegra_soc_attr_group, };#endif
@@ -348,5 +353,6 @@ const struct tegra_fuse_soc tegra194_fuse_soc = { .info = &tegra194_fuse_info, .lookups = tegra194_fuse_lookups, .num_lookups = ARRAY_SIZE(tegra194_fuse_lookups), + .soc_attr_group = &tegra194_soc_attr_group, };#endif
drivers/soc/tegra/fuse/fuse.h +8 -0
@@ -32,6 +32,8 @@ struct tegra_fuse_soc {const struct nvmem_cell_lookup *lookups;unsigned int num_lookups; + +const struct attribute_group *soc_attr_group; };struct tegra_fuse {
@@ -64,6 +66,11 @@ void tegra_init_apbmisc(void);bool __init tegra_fuse_read_spare (unsigned int spare);u32 __init tegra_fuse_read_early (unsigned int offset); +u8 tegra_get_major_rev (void ); +u8 tegra_get_minor_rev (void ); + +extern const struct attribute_group tegra_soc_attr_group; +#ifdef CONFIG_ARCH_TEGRA_2x_SOCvoid tegra20_init_speedo_data (struct tegra_sku_info *sku_info);#endif
@@ -110,6 +117,7 @@ extern const struct tegra_fuse_soc tegra186_fuse_soc;#ifdef CONFIG_ARCH_TEGRA_194_SOC extern const struct tegra_fuse_soc tegra194_fuse_soc; +extern const struct attribute_group tegra194_soc_attr_group;#endif #endif
drivers/soc/tegra/fuse/tegra-apbmisc.c +10 -0
@@ -37,6 +37,16 @@ u8 tegra_get_chip_id(void)return (tegra_read_chipid () >>8 ) &0xff ; } +u8 tegra_get_major_rev (void ) +{ +return (tegra_read_chipid () >>4 ) &0xf ; +} + +u8 tegra_get_minor_rev (void ) +{ +return (tegra_read_chipid () >>16 ) &0xf ; +} +u32 tegra_read_straps (void ) {WARN (!chipid,"Tegra ABP MISC not yet available\n" );
Signature · 1 line
2.17.1
Jon Hunter
maintainerPATCH v2 2/3 soc/tegra: fuse: Correct Tegra194 revision
Determining the revision for Tegra194 devices is slightly different from previous generations. For Tegra194, the majorrev field of the HIDREV register determines if the major revision is A, B, C, etc and the minorrev field determines if the minorrev is 01, 02, 03, etc.
For Tegra194, there are two main revisions which are A01 and A02. Therefore, add a new function to correctly identify the revision for Tegra194 devices.
--- drivers/soc/tegra/fuse/fuse-tegra20.c | 3 ++- drivers/soc/tegra/fuse/fuse-tegra30.c | 8 ++++++- drivers/soc/tegra/fuse/fuse.h | 2 ++ drivers/soc/tegra/fuse/tegra-apbmisc.c | 29 ++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-)
drivers/soc/tegra/fuse/fuse-tegra20.c +2 -1
@@ -154,13 +154,14 @@ static void __init tegra20_fuse_init(struct tegra_fuse *fuse) { fuse->read_early = tegra20_fuse_read_early; -tegra_init_revision (); + fuse->soc->revision_init (); fuse->soc->speedo_init (&tegra_sku_info);tegra20_fuse_add_randomness (); }const struct tegra_fuse_soc tegra20_fuse_soc = { .init = tegra20_fuse_init, + .revision_init = tegra_init_revision, .speedo_init = tegra20_init_speedo_data, .probe = tegra20_fuse_probe, .info = &tegra20_fuse_info,
drivers/soc/tegra/fuse/fuse-tegra30.c +7 -1
@@ -91,7 +91,7 @@ static void __init tegra30_fuse_init(struct tegra_fuse *fuse) fuse->read_early = tegra30_fuse_read_early; fuse->read = tegra30_fuse_read; -tegra_init_revision (); + fuse->soc->revision_init ();if (fuse->soc->speedo_init) fuse->soc->speedo_init (&tegra_sku_info);
@@ -110,6 +110,7 @@ static const struct tegra_fuse_info tegra30_fuse_info = {const struct tegra_fuse_soc tegra30_fuse_soc = { .init = tegra30_fuse_init, .speedo_init = tegra30_init_speedo_data, + .revision_init = tegra_init_revision, .info = &tegra30_fuse_info, .soc_attr_group = &tegra_soc_attr_group, };
@@ -125,6 +126,7 @@ static const struct tegra_fuse_info tegra114_fuse_info = {const struct tegra_fuse_soc tegra114_fuse_soc = { .init = tegra30_fuse_init, .speedo_init = tegra114_init_speedo_data, + .revision_init = tegra_init_revision, .info = &tegra114_fuse_info, .soc_attr_group = &tegra_soc_attr_group, };
@@ -204,6 +206,7 @@ static const struct tegra_fuse_info tegra124_fuse_info = {const struct tegra_fuse_soc tegra124_fuse_soc = { .init = tegra30_fuse_init, .speedo_init = tegra124_init_speedo_data, + .revision_init = tegra_init_revision, .info = &tegra124_fuse_info, .lookups = tegra124_fuse_lookups, .num_lookups =ARRAY_SIZE (tegra124_fuse_lookups),
@@ -290,6 +293,7 @@ static const struct tegra_fuse_info tegra210_fuse_info = {const struct tegra_fuse_soc tegra210_fuse_soc = { .init = tegra30_fuse_init, .speedo_init = tegra210_init_speedo_data, + .revision_init = tegra_init_revision, .info = &tegra210_fuse_info, .lookups = tegra210_fuse_lookups, .num_lookups =ARRAY_SIZE (tegra210_fuse_lookups),
@@ -320,6 +324,7 @@ static const struct tegra_fuse_info tegra186_fuse_info = {const struct tegra_fuse_soc tegra186_fuse_soc = { .init = tegra30_fuse_init, + .revision_init = tegra_init_revision, .info = &tegra186_fuse_info, .lookups = tegra186_fuse_lookups, .num_lookups =ARRAY_SIZE (tegra186_fuse_lookups),
@@ -350,6 +355,7 @@ static const struct tegra_fuse_info tegra194_fuse_info = {const struct tegra_fuse_soc tegra194_fuse_soc = { .init = tegra30_fuse_init, + .revision_init = tegra194_init_revision, .info = &tegra194_fuse_info, .lookups = tegra194_fuse_lookups, .num_lookups =ARRAY_SIZE (tegra194_fuse_lookups),
drivers/soc/tegra/fuse/fuse.h +2 -0
@@ -26,6 +26,7 @@ struct tegra_fuse_info {struct tegra_fuse_soc {void (*init)(struct tegra_fuse *fuse);void (*speedo_init)(struct tegra_sku_info *info); +void (*revision_init)(void );int (*probe)(struct tegra_fuse *fuse);const struct tegra_fuse_info *info;
@@ -61,6 +62,7 @@ struct tegra_fuse { };void tegra_init_revision (void ); +void tegra194_init_revision (void );void tegra_init_apbmisc (void );bool __init tegra_fuse_read_spare (unsigned int spare);
drivers/soc/tegra/fuse/tegra-apbmisc.c +29 -0
@@ -108,6 +108,35 @@ void __init tegra_init_revision(void) tegra_sku_info.sku_id =tegra_fuse_read_early (FUSE_SKU_INFO ); } +void __init tegra194_init_revision (void ) +{ +u8 major_rev, minor_rev; + + major_rev =tegra_get_major_rev (); + minor_rev =tegra_get_minor_rev (); + +switch (major_rev) { +case 1 : +switch (minor_rev) { +case 1 : + tegra_sku_info.revision =TEGRA_REVISION_A01 ; +break ; +case 2 : + tegra_sku_info.revision =TEGRA_REVISION_A02 ; +break ; +default : + tegra_sku_info.revision =TEGRA_REVISION_UNKNOWN ; +break ; + } +break ; +default : + tegra_sku_info.revision =TEGRA_REVISION_UNKNOWN ; +break ; + } + + tegra_sku_info.sku_id =tegra_fuse_read_early (FUSE_SKU_INFO ); +} +void __init tegra_init_apbmisc (void ) {void __iomem *apbmisc_base, *strapping_base;
Signature · 1 line
2.17.1
Jon Hunter
maintainerRe: [PATCH V2 2/3] soc/tegra: fuse: Correct Tegra194 revision
Quoted 9 lines · Jon Hunter
Determining the revision for Tegra194 devices is slightly different from previous generations. For Tegra194, the majorrev field of the HIDREV register determines if the major revision is A, B, C, etc and the minorrev field determines if the minorrev is 01, 02, 03, etc.
For Tegra194, there are two main revisions which are A01 and A02. Therefore, add a new function to correctly identify the revision for Tegra194 devices.
Quoted 7 lines
Signed-off-by Jon Hunter <[email protected]>--- drivers/soc/tegra/fuse/fuse-tegra20.c | 3 ++- drivers/soc/tegra/fuse/fuse-tegra30.c | 8 ++++++- drivers/soc/tegra/fuse/fuse.h | 2 ++ drivers/soc/tegra/fuse/tegra-apbmisc.c | 29 ++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-)
Although there is a slight difference, it turns out that the existing code does work fine for Tegra194 as well and so I will drop this change as it is not needed.
Jon
Signature · 1 line
nvpublic
Jon Hunter
maintainerPATCH v2 3/3 soc/tegra: fuse: Trivial clean-up of tegra_init_revision()
In reply to Jon HunterClean-up the tegra_init_revision() function by removing the 'rev' variable which is not needed and use the newly added helper function tegra_get_minor_rev() to get the minor revision.
--- drivers/soc/tegra/fuse/tegra-apbmisc.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-)
drivers/soc/tegra/fuse/tegra-apbmisc.c +9 -13
@@ -75,36 +75,32 @@ static const struct of_device_id apbmisc_match[] __initconst = {void __init tegra_init_revision (void ) { -u32 id, chip_id, minor_rev; -int rev; +u8 chip_id, minor_rev; - id =tegra_read_chipid (); - chip_id = (id >>8 ) &0xff ; - minor_rev = (id >>16 ) &0xf ; + chip_id =tegra_get_chip_id (); + minor_rev =tegra_get_minor_rev ();switch (minor_rev) {case 1 : - rev =TEGRA_REVISION_A01 ; + tegra_sku_info.revision =TEGRA_REVISION_A01 ;break ;case 2 : - rev =TEGRA_REVISION_A02 ; + tegra_sku_info.revision =TEGRA_REVISION_A02 ;break ;case 3 :if (chip_id ==TEGRA20 && (tegra_fuse_read_spare (18 ) ||tegra_fuse_read_spare (19 ))) - rev = TEGRA_REVISION_A03p; + tegra_sku_info.revision = TEGRA_REVISION_A03p;else - rev =TEGRA_REVISION_A03 ; + tegra_sku_info.revision =TEGRA_REVISION_A03 ;break ;case 4 : - rev =TEGRA_REVISION_A04 ; + tegra_sku_info.revision =TEGRA_REVISION_A04 ;break ;default : - rev =TEGRA_REVISION_UNKNOWN ; + tegra_sku_info.revision =TEGRA_REVISION_UNKNOWN ; } - tegra_sku_info.revision = rev; - tegra_sku_info.sku_id =tegra_fuse_read_early (FUSE_SKU_INFO ); }
Signature · 1 line
2.17.1
31.03.2020 13:33, Jon Hunter пишет:
Quoted 39 lines
Add a custom SoC attribute for Tegra to expose the HIDREV register fields to userspace via the sysfs. This register provides additional details about the type of device (eg, silicon, FPGA, etc) as well as revision. Exposing this information is useful for identifying the exact device revision and device type.
For Tegra devices up until Tegra186, the majorrev and minorrev fields of the HIDREV register are used to determine the device revision and device type. For Tegra194, the majorrev and minorrev fields only determine the revision. Starting with Tegra194, there is an additional field,
pre_si_platform(which occupies bits 20-23), that now determines device type. Therefore, for all Tegra devices, add a custom SoC attribute for the majorrev and minorrev fields and for Tegra194 add an additional attribute for thepre_si_platformfield.Signed-off-by Jon Hunter <[email protected]>--- drivers/soc/tegra/fuse/fuse-tegra.c | 51 ++++++++++++++++++++++++++ drivers/soc/tegra/fuse/fuse-tegra20.c | 1 + drivers/soc/tegra/fuse/fuse-tegra30.c | 6 +++ drivers/soc/tegra/fuse/fuse.h | 8 ++++ drivers/soc/tegra/fuse/tegra-apbmisc.c | 10 +++++ 5 files changed, 76 insertions(+)drivers/soc/tegra/fuse/fuse-tegra.c +7
-0@@ -300,6 +300,56 @@ static void tegra_enable_fuse_clk(void __iomem *base)writel (reg, base +0x14 ); } +static ssize_t tegra_soc_majorrev_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +return sprintf (buf,"%d\n" ,tegra_get_major_rev ()); +} +
drivers/soc/tegra/fuse/fuse-tegra.c static void tegra_enable_fuse_clk(void __iomem *base) · line 319
Quoted 10 lines
drivers/soc/tegra/fuse/fuse-tegra.c +10
-0+static DEVICE_ATTR(majorrev, S_IRUGO, tegra_soc_majorrev_show, NULL); + +static ssize_t tegra_soc_minorrev_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +return sprintf (buf,"%d\n" ,tegra_get_minor_rev ()); +} + +static DEVICE_ATTR(minorrev, S_IRUGO, tegra_soc_minorrev_show, NULL);
Checkpatch should give a warning about that permission isn't in octal format, please don't ignore it.
Jon Hunter
maintainerQuoted 45 lines · Dmitry Osipenko
31.03.2020 13:33, Jon Hunter пишет:
Quoted 44 lines
Add a custom SoC attribute for Tegra to expose the HIDREV register fields to userspace via the sysfs. This register provides additional details about the type of device (eg, silicon, FPGA, etc) as well as revision. Exposing this information is useful for identifying the exact device revision and device type.
For Tegra devices up until Tegra186, the majorrev and minorrev fields of the HIDREV register are used to determine the device revision and device type. For Tegra194, the majorrev and minorrev fields only determine the revision. Starting with Tegra194, there is an additional field,
pre_si_platform(which occupies bits 20-23), that now determines device type. Therefore, for all Tegra devices, add a custom SoC attribute for the majorrev and minorrev fields and for Tegra194 add an additional attribute for thepre_si_platformfield.Signed-off-by Jon Hunter <[email protected]>--- drivers/soc/tegra/fuse/fuse-tegra.c | 51 ++++++++++++++++++++++++++ drivers/soc/tegra/fuse/fuse-tegra20.c | 1 + drivers/soc/tegra/fuse/fuse-tegra30.c | 6 +++ drivers/soc/tegra/fuse/fuse.h | 8 ++++ drivers/soc/tegra/fuse/tegra-apbmisc.c | 10 +++++ 5 files changed, 76 insertions(+)drivers/soc/tegra/fuse/fuse-tegra.c +12
-0@@ -300,6 +300,56 @@ static void tegra_enable_fuse_clk(void __iomem *base)writel (reg, base +0x14 ); } +static ssize_t tegra_soc_majorrev_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +return sprintf (buf,"%d\n" ,tegra_get_major_rev ()); +} + +static DEVICE_ATTR(majorrev, S_IRUGO, tegra_soc_majorrev_show, NULL); + +static ssize_t tegra_soc_minorrev_show (struct device *dev, +struct device_attribute *attr, +char *buf)
Quoted 8 lines
drivers/soc/tegra/fuse/fuse-tegra.c static void tegra_enable_fuse_clk(void __iomem *base) · line 319
Quoted 5 lines
drivers/soc/tegra/fuse/fuse-tegra.c +5
-0+{ +return sprintf (buf,"%d\n" ,tegra_get_minor_rev ()); +} + +static DEVICE_ATTR(minorrev, S_IRUGO, tegra_soc_minorrev_show, NULL);Checkpatch should give a warning about that permission isn't in octal format, please don't ignore it.
Indeed. Will fix. I thought I had ran this previously, obviously not.
Jon
Signature · 1 line
nvpublic
31.03.2020 16:56, Jon Hunter пишет:
...
Quoted 6 lines
Quoted 4 lines
Quoted 1 line
+static
DEVICE_ATTR(minorrev, S_IRUGO, tegra_soc_minorrev_show, NULL);Checkpatch should give a warning about that permission isn't in octal format, please don't ignore it.
Indeed. Will fix. I thought I had ran this previously, obviously not.
Also, please use DEVICE_ATTR_RO().