diff options
| author | Pekka Pessi <ppessi@nvidia.com> | 2018-08-20 13:25:22 -0400 |
|---|---|---|
| committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2018-09-12 20:47:24 -0400 |
| commit | a16f79eeff8f61dccc679dd84a0ecb1f138c506e (patch) | |
| tree | abca699a8e25f576a258c51c17b43cb11eb17399 | |
| parent | c100fa4ba34599cde78e770785a6c8949a14b34b (diff) | |
tegra: camera: rtcpu: fix boot timeouts
The t186-sce boot time sometimes exceeds 2000 milliseconds. The undue
boot time is because the memory bandwidth problems. During the boot
the DRAM image is read twice (once when copying, once when calculating
SHA1).
Calculate time from deasserting resets to the first mailbox handshake
with camrtc.
Add a dedicated bandwidth manager client for camrtc. Request for extra
memory bandwidth during boot time.
Retry camrtc boot if it fails.
Report failed boot handshake correctly to the platform, avoid
corruption.
Bug 2305627
Change-Id: Ia96e369ee1b09d6298268f7bd309db1c8f326564
Signed-off-by: Pekka Pessi <ppessi@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1803895
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Semi Malinen <smalinen@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
| -rw-r--r-- | drivers/platform/tegra/tegra-camera-rtcpu.c | 139 | ||||
| -rw-r--r-- | include/linux/platform/tegra/emc_bwmgr.h | 1 |
2 files changed, 117 insertions, 23 deletions
diff --git a/drivers/platform/tegra/tegra-camera-rtcpu.c b/drivers/platform/tegra/tegra-camera-rtcpu.c index 0e4fc172a..4b2900248 100644 --- a/drivers/platform/tegra/tegra-camera-rtcpu.c +++ b/drivers/platform/tegra/tegra-camera-rtcpu.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <linux/of_irq.h> | 31 | #include <linux/of_irq.h> |
| 32 | #include <linux/of_platform.h> | 32 | #include <linux/of_platform.h> |
| 33 | #include <linux/platform_device.h> | 33 | #include <linux/platform_device.h> |
| 34 | #include <linux/platform/tegra/emc_bwmgr.h> | ||
| 34 | #include <linux/pm_runtime.h> | 35 | #include <linux/pm_runtime.h> |
| 35 | #include <linux/sched.h> | 36 | #include <linux/sched.h> |
| 36 | #include <linux/seq_buf.h> | 37 | #include <linux/seq_buf.h> |
| @@ -201,6 +202,10 @@ struct tegra_cam_rtcpu { | |||
| 201 | } cmd; | 202 | } cmd; |
| 202 | u32 fw_version; | 203 | u32 fw_version; |
| 203 | u8 fw_hash[RTCPU_FW_HASH_SIZE]; | 204 | u8 fw_hash[RTCPU_FW_HASH_SIZE]; |
| 205 | struct { | ||
| 206 | u64 reset_complete; | ||
| 207 | u64 boot_handshake; | ||
| 208 | } stats; | ||
| 204 | union { | 209 | union { |
| 205 | void __iomem *regs[CAMRTC_NUM_REGS]; | 210 | void __iomem *regs[CAMRTC_NUM_REGS]; |
| 206 | struct { | 211 | struct { |
| @@ -221,7 +226,10 @@ struct tegra_cam_rtcpu { | |||
| 221 | }; | 226 | }; |
| 222 | const struct tegra_cam_rtcpu_pdata *pdata; | 227 | const struct tegra_cam_rtcpu_pdata *pdata; |
| 223 | struct camrtc_device_group *camera_devices; | 228 | struct camrtc_device_group *camera_devices; |
| 229 | struct tegra_bwmgr_client *bwmgr; | ||
| 224 | struct tegra_camrtc_mon *monitor; | 230 | struct tegra_camrtc_mon *monitor; |
| 231 | unsigned long full_bw; | ||
| 232 | u32 max_reboot_retry; | ||
| 225 | bool powered; | 233 | bool powered; |
| 226 | bool boot_sync_done; | 234 | bool boot_sync_done; |
| 227 | bool online; | 235 | bool online; |
| @@ -375,11 +383,64 @@ static void tegra_camrtc_assert_resets(struct device *dev) | |||
| 375 | static int tegra_camrtc_deassert_resets(struct device *dev) | 383 | static int tegra_camrtc_deassert_resets(struct device *dev) |
| 376 | { | 384 | { |
| 377 | struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); | 385 | struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); |
| 386 | int ret = 0; | ||
| 378 | 387 | ||
| 379 | if (rtcpu->pdata->deassert_resets) | 388 | if (rtcpu->pdata->deassert_resets) { |
| 380 | return rtcpu->pdata->deassert_resets(dev); | 389 | ret = rtcpu->pdata->deassert_resets(dev); |
| 390 | rtcpu->stats.reset_complete = ktime_get_ns(); | ||
| 391 | rtcpu->stats.boot_handshake = 0; | ||
| 392 | } | ||
| 381 | 393 | ||
| 382 | return 0; | 394 | return ret; |
| 395 | } | ||
| 396 | |||
| 397 | static void tegra_camrtc_init_bwmgr(struct device *dev) | ||
| 398 | { | ||
| 399 | struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); | ||
| 400 | u32 bw; | ||
| 401 | |||
| 402 | if (of_property_read_u32(dev->of_node, NV(memory-bw), &bw) != 0) | ||
| 403 | return; | ||
| 404 | |||
| 405 | if (bw == 0xFFFFFFFFU) | ||
| 406 | rtcpu->full_bw = tegra_bwmgr_get_max_emc_rate(); | ||
| 407 | else | ||
| 408 | rtcpu->full_bw = tegra_bwmgr_round_rate(bw); | ||
| 409 | |||
| 410 | rtcpu->bwmgr = tegra_bwmgr_register(TEGRA_BWMGR_CLIENT_CAMRTC); | ||
| 411 | |||
| 412 | if (IS_ERR_OR_NULL(rtcpu->bwmgr)) { | ||
| 413 | dev_warn(dev, "no memory bw manager\n"); | ||
| 414 | rtcpu->bwmgr = NULL; | ||
| 415 | return; | ||
| 416 | } | ||
| 417 | |||
| 418 | dev_dbg(dev, "using emc rate %lu for power-on\n", rtcpu->full_bw); | ||
| 419 | } | ||
| 420 | |||
| 421 | static void tegra_camrtc_full_mem_bw(struct device *dev) | ||
| 422 | { | ||
| 423 | struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); | ||
| 424 | |||
| 425 | if (rtcpu->bwmgr != NULL) { | ||
| 426 | int ret = tegra_bwmgr_set_emc(rtcpu->bwmgr, rtcpu->full_bw, | ||
| 427 | TEGRA_BWMGR_SET_EMC_FLOOR); | ||
| 428 | if (ret < 0) | ||
| 429 | dev_info(dev, "emc request rate %lu failed, %d\n", | ||
| 430 | rtcpu->full_bw, ret); | ||
| 431 | else | ||
| 432 | dev_dbg(dev, "requested emc rate %lu\n", | ||
| 433 | rtcpu->full_bw); | ||
| 434 | } | ||
| 435 | } | ||
| 436 | |||
| 437 | static void tegra_camrtc_slow_mem_bw(struct device *dev) | ||
| 438 | { | ||
| 439 | struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); | ||
| 440 | |||
| 441 | if (rtcpu->bwmgr != NULL) | ||
| 442 | (void)tegra_bwmgr_set_emc(rtcpu->bwmgr, 0, | ||
| 443 | TEGRA_BWMGR_SET_EMC_FLOOR); | ||
| 383 | } | 444 | } |
| 384 | 445 | ||
| 385 | /* | 446 | /* |
| @@ -788,8 +849,10 @@ static int tegra_camrtc_poweron(struct device *dev, bool full_speed) | |||
| 788 | } | 849 | } |
| 789 | 850 | ||
| 790 | /* APE power domain may misbehave and try to resume while probing */ | 851 | /* APE power domain may misbehave and try to resume while probing */ |
| 791 | if (rtcpu->sm_pair == NULL) | 852 | if (rtcpu->sm_pair == NULL) { |
| 853 | dev_info(dev, "poweron while probing"); | ||
| 792 | return 0; | 854 | return 0; |
| 855 | } | ||
| 793 | 856 | ||
| 794 | /* Power on and let core run */ | 857 | /* Power on and let core run */ |
| 795 | ret = tegra_camrtc_enable_clks(dev); | 858 | ret = tegra_camrtc_enable_clks(dev); |
| @@ -846,6 +909,18 @@ static int tegra_camrtc_boot_sync(struct device *dev) | |||
| 846 | return -EIO; | 909 | return -EIO; |
| 847 | } | 910 | } |
| 848 | 911 | ||
| 912 | if (rtcpu->stats.boot_handshake == 0) { | ||
| 913 | u64 bt; | ||
| 914 | |||
| 915 | rtcpu->stats.boot_handshake = ktime_get_ns(); | ||
| 916 | |||
| 917 | bt = rtcpu->stats.boot_handshake - | ||
| 918 | rtcpu->stats.reset_complete + 500U; | ||
| 919 | |||
| 920 | dev_dbg(dev, "boot time %llu.%03u ms\n", bt / 1000000U, | ||
| 921 | (unsigned int)(bt % 10000000U) / 1000U); | ||
| 922 | } | ||
| 923 | |||
| 849 | command = RTCPU_COMMAND(FW_VERSION, RTCPU_DRIVER_SM5_VERSION); | 924 | command = RTCPU_COMMAND(FW_VERSION, RTCPU_DRIVER_SM5_VERSION); |
| 850 | ret = tegra_camrtc_command(dev, command, 0); | 925 | ret = tegra_camrtc_command(dev, command, 0); |
| 851 | if (ret < 0) | 926 | if (ret < 0) |
| @@ -866,7 +941,7 @@ static int tegra_camrtc_boot_sync(struct device *dev) | |||
| 866 | ret = tegra_rtcpu_trace_boot_sync(rtcpu->tracer); | 941 | ret = tegra_rtcpu_trace_boot_sync(rtcpu->tracer); |
| 867 | if (ret < 0) { | 942 | if (ret < 0) { |
| 868 | dev_err(dev, "trace boot sync failed: %d\n", ret); | 943 | dev_err(dev, "trace boot sync failed: %d\n", ret); |
| 869 | goto error; | 944 | return ret; |
| 870 | } | 945 | } |
| 871 | } | 946 | } |
| 872 | 947 | ||
| @@ -886,9 +961,6 @@ static int tegra_camrtc_boot_sync(struct device *dev) | |||
| 886 | } | 961 | } |
| 887 | 962 | ||
| 888 | return 0; | 963 | return 0; |
| 889 | |||
| 890 | error: | ||
| 891 | return ret; | ||
| 892 | } | 964 | } |
| 893 | 965 | ||
| 894 | /* | 966 | /* |
| @@ -896,17 +968,35 @@ error: | |||
| 896 | */ | 968 | */ |
| 897 | static int tegra_camrtc_boot(struct device *dev) | 969 | static int tegra_camrtc_boot(struct device *dev) |
| 898 | { | 970 | { |
| 971 | struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); | ||
| 972 | int retry = 0, max_retries = rtcpu->max_reboot_retry; | ||
| 899 | int ret; | 973 | int ret; |
| 900 | 974 | ||
| 901 | ret = tegra_camrtc_poweron(dev, true); | 975 | ret = tegra_camrtc_poweron(dev, true); |
| 902 | if (ret) | 976 | if (ret) |
| 903 | return ret; | 977 | return ret; |
| 904 | 978 | ||
| 905 | ret = tegra_camrtc_boot_sync(dev); | 979 | tegra_camrtc_full_mem_bw(dev); |
| 980 | |||
| 981 | for (;;) { | ||
| 982 | ret = tegra_camrtc_boot_sync(dev); | ||
| 983 | if (ret == 0) | ||
| 984 | break; | ||
| 985 | if (retry++ == max_retries) | ||
| 986 | break; | ||
| 987 | dev_warn(dev, "%s full reset, retry %u/%u\n", | ||
| 988 | rtcpu->name, retry, max_retries); | ||
| 989 | tegra_camrtc_assert_resets(dev); | ||
| 990 | usleep_range(10, 30); | ||
| 991 | tegra_camrtc_deassert_resets(dev); | ||
| 992 | } | ||
| 993 | |||
| 906 | if (ret == 0) { | 994 | if (ret == 0) { |
| 907 | tegra_camrtc_set_online(dev, true); | 995 | tegra_camrtc_set_online(dev, true); |
| 908 | } | 996 | } |
| 909 | 997 | ||
| 998 | tegra_camrtc_slow_mem_bw(dev); | ||
| 999 | |||
| 910 | return 0; | 1000 | return 0; |
| 911 | } | 1001 | } |
| 912 | 1002 | ||
| @@ -1012,19 +1102,11 @@ static int tegra_cam_rtcpu_runtime_resume(struct device *dev) | |||
| 1012 | if (ret < 0) | 1102 | if (ret < 0) |
| 1013 | return ret; | 1103 | return ret; |
| 1014 | 1104 | ||
| 1015 | ret = tegra_camrtc_poweron(dev, true); | 1105 | ret = tegra_camrtc_boot(dev); |
| 1016 | if (ret) | ||
| 1017 | goto error; | ||
| 1018 | |||
| 1019 | ret = tegra_camrtc_boot_sync(dev); | ||
| 1020 | if (ret) | ||
| 1021 | goto error; | ||
| 1022 | 1106 | ||
| 1023 | tegra_camrtc_set_online(dev, true); | 1107 | if (ret < 0) |
| 1108 | camrtc_device_group_idle(rtcpu->camera_devices); | ||
| 1024 | 1109 | ||
| 1025 | return 0; | ||
| 1026 | error: | ||
| 1027 | camrtc_device_group_idle(rtcpu->camera_devices); | ||
| 1028 | return ret; | 1110 | return ret; |
| 1029 | } | 1111 | } |
| 1030 | 1112 | ||
| @@ -1120,10 +1202,14 @@ static int tegra_cam_rtcpu_remove(struct platform_device *pdev) | |||
| 1120 | } | 1202 | } |
| 1121 | 1203 | ||
| 1122 | tegra_rtcpu_trace_destroy(rtcpu->tracer); | 1204 | tegra_rtcpu_trace_destroy(rtcpu->tracer); |
| 1123 | if (rtcpu->coverage != NULL) | 1205 | rtcpu->tracer = NULL; |
| 1124 | tegra_rtcpu_coverage_destroy(rtcpu->coverage); | 1206 | tegra_rtcpu_coverage_destroy(rtcpu->coverage); |
| 1207 | rtcpu->coverage = NULL; | ||
| 1125 | 1208 | ||
| 1126 | tegra_camrtc_poweroff(&pdev->dev); | 1209 | tegra_camrtc_poweroff(&pdev->dev); |
| 1210 | if (rtcpu->bwmgr != NULL) | ||
| 1211 | tegra_bwmgr_unregister(rtcpu->bwmgr); | ||
| 1212 | rtcpu->bwmgr = NULL; | ||
| 1127 | tegra_pd_remove_device(&pdev->dev); | 1213 | tegra_pd_remove_device(&pdev->dev); |
| 1128 | tegra_cam_rtcpu_mon_destroy(rtcpu->monitor); | 1214 | tegra_cam_rtcpu_mon_destroy(rtcpu->monitor); |
| 1129 | tegra_ivc_bus_destroy(rtcpu->ivc); | 1215 | tegra_ivc_bus_destroy(rtcpu->ivc); |
| @@ -1170,6 +1256,10 @@ static int tegra_cam_rtcpu_probe(struct platform_device *pdev) | |||
| 1170 | if (ret) | 1256 | if (ret) |
| 1171 | goto fail; | 1257 | goto fail; |
| 1172 | 1258 | ||
| 1259 | rtcpu->max_reboot_retry = 2; | ||
| 1260 | (void)of_property_read_u32(dev->of_node, NV(max-reboot), | ||
| 1261 | &rtcpu->max_reboot_retry); | ||
| 1262 | |||
| 1173 | timeout = 2000; | 1263 | timeout = 2000; |
| 1174 | (void)of_property_read_u32(dev->of_node, NV(cmd-timeout), &timeout); | 1264 | (void)of_property_read_u32(dev->of_node, NV(cmd-timeout), &timeout); |
| 1175 | rtcpu->cmd.timeout = msecs_to_jiffies(timeout); | 1265 | rtcpu->cmd.timeout = msecs_to_jiffies(timeout); |
| @@ -1181,6 +1271,8 @@ static int tegra_cam_rtcpu_probe(struct platform_device *pdev) | |||
| 1181 | pm_runtime_set_autosuspend_delay(&pdev->dev, timeout); | 1271 | pm_runtime_set_autosuspend_delay(&pdev->dev, timeout); |
| 1182 | } | 1272 | } |
| 1183 | 1273 | ||
| 1274 | tegra_camrtc_init_bwmgr(dev); | ||
| 1275 | |||
| 1184 | dev->dma_parms = &rtcpu->dma_parms; | 1276 | dev->dma_parms = &rtcpu->dma_parms; |
| 1185 | dma_set_max_seg_size(dev, UINT_MAX); | 1277 | dma_set_max_seg_size(dev, UINT_MAX); |
| 1186 | 1278 | ||
| @@ -1193,7 +1285,8 @@ static int tegra_cam_rtcpu_probe(struct platform_device *pdev) | |||
| 1193 | goto fail; | 1285 | goto fail; |
| 1194 | 1286 | ||
| 1195 | /* Power on device */ | 1287 | /* Power on device */ |
| 1196 | if (pm_runtime_get_sync(dev) < 0) | 1288 | ret = pm_runtime_get_sync(dev); |
| 1289 | if (ret < 0) | ||
| 1197 | goto fail; | 1290 | goto fail; |
| 1198 | 1291 | ||
| 1199 | /* Clocks are on, resets are deasserted, we can touch the hardware */ | 1292 | /* Clocks are on, resets are deasserted, we can touch the hardware */ |
diff --git a/include/linux/platform/tegra/emc_bwmgr.h b/include/linux/platform/tegra/emc_bwmgr.h index 64d6f6f89..cbc79b03b 100644 --- a/include/linux/platform/tegra/emc_bwmgr.h +++ b/include/linux/platform/tegra/emc_bwmgr.h | |||
| @@ -50,6 +50,7 @@ enum tegra_bwmgr_client_id { | |||
| 50 | TEGRA_BWMGR_CLIENT_ISPB, | 50 | TEGRA_BWMGR_CLIENT_ISPB, |
| 51 | TEGRA_BWMGR_CLIENT_CAMERA, | 51 | TEGRA_BWMGR_CLIENT_CAMERA, |
| 52 | TEGRA_BWMGR_CLIENT_CAMERA_NON_ISO, | 52 | TEGRA_BWMGR_CLIENT_CAMERA_NON_ISO, |
| 53 | TEGRA_BWMGR_CLIENT_CAMRTC, | ||
| 53 | TEGRA_BWMGR_CLIENT_ISOMGR, | 54 | TEGRA_BWMGR_CLIENT_ISOMGR, |
| 54 | TEGRA_BWMGR_CLIENT_THERMAL_CAP, | 55 | TEGRA_BWMGR_CLIENT_THERMAL_CAP, |
| 55 | TEGRA_BWMGR_CLIENT_VIC, | 56 | TEGRA_BWMGR_CLIENT_VIC, |
