Commit Graph

15 Commits

Author SHA1 Message Date
Christophe JAILLET 32eb645332 cpufreq: tegra186: Use flexible array to simplify memory allocation
Use flexible array to simplify memory allocation.
It saves some memory, avoids an indirection when reading the 'clusters'
array and removes some LoC.

Detailed explanation:
====================
Knowing that:
  - each devm_ allocation over-allocates 40 bytes for internal needs
  - Some rounding is done by the memory allocator on 8, 16, 32, 64, 96,
    128, 192, 256, 512, 1024, 2048, 4096, 8192 boundaries

and that:
  - sizeof(struct tegra186_cpufreq_data) = 24
  - sizeof(struct tegra186_cpufreq_cluster) = 16

Memory allocations in tegra186_cpufreq_probe() are:
  data:           (24 + 40) = 64 		      => 64 bytes
  data->clusters: (2 * 16 + 40) = 72     => 96 bytes
So a total of 160 bytes are allocated.
56 for the real need, 80 for internal uses and 24 are wasted.

If 'struct tegra186_cpufreq_data' is reordered so that 'clusters' is a
flexible array:
  - it saves one pointer in the structure
  - only one allocation is needed

So, only 96 bytes are allocated:
  16 + 2 * 16 + 40 = 88  => 96 bytes

Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
2022-12-01 14:49:50 +05:30
Mikko Perttunen c2ace21f93 cpufreq: tegra186/tegra194: Handle errors in BPMP response
The return value from tegra_bpmp_transfer indicates the success or
failure of the IPC transaction with BPMP. If the transaction
succeeded, we also need to check the actual command's result code.
Add code to do this.

While at it, explicitly handle missing CPU clusters, which can
occur on floorswept chips. This worked before as well, but
possibly only by accident.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
2021-10-04 12:31:36 +05:30
Viresh Kumar 5ae4a4b45d cpufreq: Remove CPUFREQ_STICKY flag
During cpufreq driver's registration, if the ->init() callback for all
the CPUs fail then there is not much point in keeping the driver around
as it will only account for more of unnecessary noise, for example
cpufreq core will try to suspend/resume the driver which never got
registered properly.

The removal of such a driver is avoided if the driver carries the
CPUFREQ_STICKY flag. This was added way back [1] in 2004 and perhaps no
one should ever need it now. A lot of drivers do set this flag, probably
because they just copied it from other drivers.

This was added earlier for some platforms [2] because their cpufreq
drivers were getting registered before the CPUs were registered with
subsys framework. And hence they used to fail.

The same isn't true anymore though. The current code flow in the kernel
is:

start_kernel()
-> kernel_init()
   -> kernel_init_freeable()
      -> do_basic_setup()
         -> driver_init()
            -> cpu_dev_init()
               -> subsys_system_register() //For CPUs

         -> do_initcalls()
            -> cpufreq_register_driver()

Clearly, the CPUs will always get registered with subsys framework
before any cpufreq driver can get probed. Remove the flag and update the
relevant drivers.

Link: https://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git/commit/include/linux/cpufreq.h?id=7cc9f0d9a1ab04cedc60d64fd8dcf7df224a3b4d # [1]
Link: https://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git/commit/arch/arm/mach-sa1100/cpu-sa1100.c?id=f59d3bbe35f6268d729f51be82af8325d62f20f5 # [2]
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2021-02-04 19:23:20 +01:00
Jon Hunter cfef4bcacc cpufreq: tegra186: Simplify cluster information lookup
The CPUFREQ driver framework references each individual CPUs when
getting and setting the speed. Tegra186 has 3 clusters of A57 CPUs and
1 cluster of Denver CPUs. Hence, the Tegra186 CPUFREQ driver need to
know which cluster a given CPU belongs to. The logic in the Tegra186
driver can be greatly simplified by storing the cluster ID associated
with each CPU in the tegra186_cpufreq_cpu structure. This allow us to
completely remove the Tegra cluster info structure from the driver and
simplifiy the code.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
2020-12-07 13:02:44 +05:30
Jon Hunter b7b4e78552 cpufreq: tegra186: Fix sparse 'incorrect type in assignment' warning
Sparse warns that the incorrect type is being assigned to the CPUFREQ
driver_data variable in the Tegra186 CPUFREQ driver. The Tegra186
CPUFREQ driver is assigned a type of 'void __iomem *' to a pointer of
type 'void *' ...

 drivers/cpufreq/tegra186-cpufreq.c:72:37: sparse: sparse: incorrect
 	type in assignment (different address spaces) @@
	expected void *driver_data @@     got void [noderef] __iomem * @@
 ...

 drivers/cpufreq/tegra186-cpufreq.c:87:40: sparse: sparse: incorrect
 	type in initializer (different address spaces) @@
	expected void [noderef] __iomem *edvd_reg @@     got void *driver_data @@

The Tegra186 CPUFREQ driver is using the policy->driver_data variable to
store and iomem pointer to a Tegra186 CPU register that is used to set
the clock speed for the CPU. This is not necessary because the register
base address is already stored in the driver data and the offset of the
register for each CPU is static. Therefore, fix this by adding a new
structure with the register offsets for each CPU and store this in the
main driver data structure along with the register base address. Please
note that a new structure has been added for storing the register
offsets rather than a simple array, because this will permit further
clean-ups and simplification of the driver.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
2020-12-07 13:02:44 +05:30
Jon Hunter e010d1d25e cpufreq: tegra186: Fix get frequency callback
Commit b89c01c960 ("cpufreq: tegra186: Fix initial frequency")
implemented the CPUFREQ 'get' callback to determine the current
operating frequency for each CPU. This implementation used a simple
looked up to determine the current operating frequency. The problem
with this is that frequency table for different Tegra186 devices may
vary and so the default boot frequency for Tegra186 device may or may
not be present in the frequency table. If the default boot frequency is
not present in the frequency table, this causes the function
tegra186_cpufreq_get() to return 0 and in turn causes cpufreq_online()
to fail which prevents CPUFREQ from working.

Fix this by always calculating the CPU frequency based upon the current
'ndiv' setting for the CPU. Note that the CPU frequency for Tegra186 is
calculated by reading the current 'ndiv' setting, multiplying by the
CPU reference clock and dividing by a constant divisor.

Fixes: b89c01c960 ("cpufreq: tegra186: Fix initial frequency")

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
2020-11-17 10:04:21 +05:30
Jon Hunter b89c01c960 cpufreq: tegra186: Fix initial frequency
Commit 6cc3d0e9a0 ("cpufreq: tegra186: add
CPUFREQ_NEED_INITIAL_FREQ_CHECK flag") fixed CPUFREQ support for
Tegra186 but as a consequence the following warnings are now seen on
boot ...

 cpufreq: cpufreq_online: CPU0: Running at unlisted freq: 0 KHz
 cpufreq: cpufreq_online: CPU0: Unlisted initial frequency changed to: 2035200 KHz
 cpufreq: cpufreq_online: CPU1: Running at unlisted freq: 0 KHz
 cpufreq: cpufreq_online: CPU1: Unlisted initial frequency changed to: 2035200 KHz
 cpufreq: cpufreq_online: CPU2: Running at unlisted freq: 0 KHz
 cpufreq: cpufreq_online: CPU2: Unlisted initial frequency changed to: 2035200 KHz
 cpufreq: cpufreq_online: CPU3: Running at unlisted freq: 0 KHz
 cpufreq: cpufreq_online: CPU3: Unlisted initial frequency changed to: 2035200 KHz
 cpufreq: cpufreq_online: CPU4: Running at unlisted freq: 0 KHz
 cpufreq: cpufreq_online: CPU4: Unlisted initial frequency changed to: 2035200 KHz
 cpufreq: cpufreq_online: CPU5: Running at unlisted freq: 0 KHz
 cpufreq: cpufreq_online: CPU5: Unlisted initial frequency changed to: 2035200 KHz

Fix this by adding a 'get' callback for the Tegra186 CPUFREQ driver to
retrieve the current operating frequency for a given CPU. The 'get'
callback uses the current 'ndiv' value that is programmed to determine
that current operating frequency.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
[ Viresh: Return 0 on error ]
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
2020-09-16 14:12:18 +05:30
Jon Hunter 02fd918097 cpufreq: tegra186: Simplify probe return path
We always put the reference to BPMP device on exit of the Tegra186
CPUFREQ driver and so there is no need to have separate exit paths
for success and failure. Therefore, simplify the probe return path
in the Tegra186 CPUFREQ driver by combining the success and failure
paths.

Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
2020-07-30 10:57:48 +05:30
Mian Yousaf Kaukab 6cc3d0e9a0 cpufreq: tegra186: add CPUFREQ_NEED_INITIAL_FREQ_CHECK flag
The driver doesn't provide ->get() method to read current frequency and
the frequency is set to 0 at initialization which makes the driver fail
at initialization time.

Set the CPUFREQ_NEED_INITIAL_FREQ_CHECK flag for the driver, so the
cpufreq core checks for the unlisted frequency and sets the CPU to a
valid frequency from the frequency table.

Signed-off-by: Mian Yousaf Kaukab <ykaukab@suse.de>
[ Viresh: Massaged change log ]
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
2020-05-18 10:58:40 +05:30
Yangtao Li 308beafc37 cpufreq: tegra186: convert to devm_platform_ioremap_resource
Use devm_platform_ioremap_resource() to simplify code.

Signed-off-by: Yangtao Li <tiny.windzz@gmail.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
2020-01-07 13:29:58 +05:30
Thomas Gleixner 2025cf9e19 treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 288
Based on 1 normalized pattern(s):

  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

extracted by the scancode license scanner the SPDX license identifier

  GPL-2.0-only

has been chosen to replace the boilerplate/reference in 263 file(s).

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Allison Randal <allison@lohutok.net>
Reviewed-by: Alexios Zavras <alexios.zavras@intel.com>
Cc: linux-spdx@vger.kernel.org
Link: https://lkml.kernel.org/r/20190529141901.208660670@linutronix.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-06-05 17:36:37 +02:00
Christoph Hellwig a3ade38d5a cpufreq: tegra186: don't pass GFP_DMA32 to dma_alloc_coherent()
The DMA API does its own zone decisions based on the coherent_dma_mask.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-10-17 09:25:38 +02:00
Viresh Kumar a8b6966034 cpufreq: tegra186: Don't validate the frequency table twice
The cpufreq core is already validating the CPU frequency table after
calling the ->init() callback of the cpufreq drivers and the drivers
don't need to do the same anymore. Though they need to set the
policy->freq_table field directly from the ->init() callback now.

Stop validating the frequency table from tegra186 driver.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-03-20 12:07:53 +01:00
Viresh Kumar 3e3b507ef6 cpufreq: tegra186: Break after initialization is done for policy->cpu
There are two clusters (2 + 4 CPUs) on this platform and a separate
cpufreq policy is available for each of the CPUs. The loop in
tegra186_cpufreq_init() tries to find the structure for the right CPU
and finish initialization. But it is missing a `break` statement at the
end, which forces it to restart the loop even when the CPU already
matched and initialization is done.

Fix that by adding the missing `break` statement.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-02-27 18:22:12 +01:00
Mikko Perttunen 939dc6f51e cpufreq: Add Tegra186 cpufreq driver
Add a new cpufreq driver for Tegra186 (and likely later).
The CPUs are organized into two clusters, Denver and A57,
with two and four cores respectively. CPU frequency can be
adjusted by writing the desired rate divisor and a voltage
hint to a special per-core register.

The frequency of each core can be set individually; however,
this is just a hint as all CPUs in a cluster will run at
the maximum rate of non-idle CPUs in the cluster.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2017-04-19 23:23:08 +02:00