diff options
| -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); | ||
