/* * drivers/video/tegra/host/t124/t124.c * * Tegra Graphics Init for T124 Architecture Chips * * Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved. * * 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "dev.h" #include "nvhost_channel.h" #include "nvhost_job.h" #include "class_ids.h" #include "t124.h" #include "host1x/host1x.h" #include "hardware_t124.h" #include "syncpt_t124.h" #include "tsec/tsec.h" #include "flcn/flcn.h" #include "isp/isp.h" #include "isp/isp_isr_v1.h" #include "scale_emc.h" #include "chip_support.h" #include "nvhost_scale.h" #include "vhost/vhost.h" #include "cg_regs.c" #define HOST_EMC_FLOOR 300000000 #define VI_AUTOSUSPEND_DELAY 500 #define ISP_AUTOSUSPEND_DELAY 500 #define TSEC_AUTOSUSPEND_DELAY 500 #define HOST1X_AUTOSUSPEND_DELAY 50 static struct host1x_device_info host1x04_info = { .nb_channels = T124_NVHOST_NUMCHANNELS, .ch_base = 0, .ch_limit = T124_NVHOST_NUMCHANNELS, .nb_mlocks = NV_HOST1X_NB_MLOCKS, .initialize_chip_support = nvhost_init_t124_support, .nb_hw_pts = NV_HOST1X_SYNCPT_NB_PTS, .nb_pts = NV_HOST1X_SYNCPT_NB_PTS, .pts_base = 0, .pts_limit = NV_HOST1X_SYNCPT_NB_PTS, .syncpt_policy = SYNCPT_PER_CHANNEL, .nb_actmons = 1, .firmware_area_size = SZ_1M, }; struct nvhost_device_data t124_host1x_info = { .clocks = {{"host1x", 81600000}, {"actmon", UINT_MAX} }, .can_powergate = true, .autosuspend_delay = HOST1X_AUTOSUSPEND_DELAY, .private_data = &host1x04_info, .finalize_poweron = nvhost_host1x_finalize_poweron, .prepare_poweroff = nvhost_host1x_prepare_poweroff, }; #ifdef CONFIG_TEGRA_GRHOST_ISP struct nvhost_device_data t124_isp_info = { .num_channels = 1, /* FIXME: control clocks from user space instead of hard-coding here */ .moduleid = NVHOST_MODULE_ISP, .class = NV_VIDEO_STREAMING_ISP_CLASS_ID, .modulemutexes = {NVMODMUTEX_ISP_0}, .devfs_name = "isp", .exclusive = true, .keepalive = true, .can_powergate = true, .autosuspend_delay = ISP_AUTOSUSPEND_DELAY, .clocks = { {"isp", UINT_MAX, 0, TEGRA_MC_CLIENT_ISP}, {"emc", 0, NVHOST_MODULE_ID_EXTERNAL_MEMORY_CONTROLLER}, {"sclk", 80000000} }, .finalize_poweron = nvhost_isp_t124_finalize_poweron, .prepare_poweroff = nvhost_isp_t124_prepare_poweroff, .hw_init = nvhost_isp_register_isr_v1, .ctrl_ops = &tegra_isp_ctrl_ops, }; struct nvhost_device_data t124_ispb_info = { .num_channels = 1, /* FIXME: control clocks from user space instead of hard-coding here */ .moduleid = (1 << 16) | NVHOST_MODULE_ISP, .devfs_name = "isp.1", .class = NV_VIDEO_STREAMING_ISPB_CLASS_ID, .modulemutexes = {NVMODMUTEX_ISP_1}, .exclusive = true, .keepalive = true, .can_powergate = true, .autosuspend_delay = ISP_AUTOSUSPEND_DELAY, .clocks = { {"isp", UINT_MAX, 0, TEGRA_MC_CLIENT_ISPB}, {"emc", 0, NVHOST_MODULE_ID_EXTERNAL_MEMORY_CONTROLLER}, {"sclk", 80000000} }, .finalize_poweron = nvhost_isp_t124_finalize_poweron, .prepare_poweroff = nvhost_isp_t124_prepare_poweroff, .hw_init = nvhost_isp_register_isr_v1, .ctrl_ops = &tegra_isp_ctrl_ops, }; #endif #if defined(CONFIG_VIDEO_TEGRA_VI) || defined(CONFIG_VIDEO_TEGRA_VI_MODULE) struct nvhost_device_data t124_vi_info = { .num_channels = 2, /* FIXME: resolve powergating dependency with DIS */ /* FIXME: control clocks from user space instead of hard-coding here */ .moduleid = NVHOST_MODULE_VI, .class = NV_VIDEO_STREAMING_VI_CLASS_ID, .modulemutexes = {NVMODMUTEX_VI_0}, .devfs_name = "vi", .exclusive = true, .keepalive = true, .can_powergate = true, .autosuspend_delay = VI_AUTOSUSPEND_DELAY, .clocks = { {"vi_bypass", UINT_MAX, 0}, {"csi", 0}, {"cilab", 102000000}, {"cilcd", 102000000}, {"cile", 102000000}, {"emc", 0, NVHOST_MODULE_ID_EXTERNAL_MEMORY_CONTROLLER}, {"sclk", 80000000} }, .prepare_poweroff = nvhost_vi_prepare_poweroff, .finalize_poweron = nvhost_vi_finalize_poweron, .ctrl_ops = &tegra_vi_ctrl_ops, .reset = nvhost_vi_reset_all, }; EXPORT_SYMBOL(t124_vi_info); #endif #if defined(CONFIG_TEGRA_GRHOST_NVENC) struct nvhost_device_data t124_msenc_info = { .num_channels = 1, .version = NVHOST_ENCODE_FLCN_VER(3, 1), .modulemutexes = {NVMODMUTEX_MSENC}, .devfs_name = "msenc", .class = NV_VIDEO_ENCODE_MSENC_CLASS_ID, .clocks = {{"msenc", UINT_MAX, 0, TEGRA_MC_CLIENT_MSENC}, {"emc", HOST_EMC_FLOOR, NVHOST_MODULE_ID_EXTERNAL_MEMORY_CONTROLLER} }, .moduleid = NVHOST_MODULE_MSENC, .autosuspend_delay = 100, .can_powergate = true, .poweron_reset = true, .finalize_poweron = nvhost_flcn_finalize_poweron, .scaling_init = nvhost_scale_init, .scaling_deinit = nvhost_scale_deinit, .actmon_regs = HOST1X_CHANNEL_ACTMON1_REG_BASE, .actmon_enabled = true, .firmware_name = "nvhost_msenc031.fw", .resource_policy = RESOURCE_PER_CHANNEL_INSTANCE, .serialize = true, }; #endif #if defined(CONFIG_TEGRA_GRHOST_TSEC) struct nvhost_device_data t124_tsec_info = { .num_channels = 1, .version = NVHOST_ENCODE_TSEC_VER(1, 0), .class = NV_TSEC_CLASS_ID, .modulemutexes = {NVMODMUTEX_TSECA}, .devfs_name = "tsec", .exclusive = false, .clocks = {{"tsec", UINT_MAX, 0, TEGRA_MC_CLIENT_TSEC}, {"emc", HOST_EMC_FLOOR} }, .can_powergate = true, .poweron_reset = true, .autosuspend_delay = TSEC_AUTOSUSPEND_DELAY, .keepalive = true, .moduleid = NVHOST_MODULE_TSEC, .finalize_poweron = nvhost_tsec_finalize_poweron, .prepare_poweroff = nvhost_tsec_prepare_poweroff, .resource_policy = RESOURCE_PER_CHANNEL_INSTANCE, .serialize = true, }; #endif #ifdef CONFIG_TEGRA_GRHOST_VIC struct nvhost_device_data t124_vic_info = { .num_channels = 1, .modulemutexes = {NVMODMUTEX_VIC}, .devfs_name = "vic", .clocks = {{"vic03", UINT_MAX, 0, TEGRA_MC_CLIENT_VIC}, {"emc", UINT_MAX, NVHOST_MODULE_ID_EXTERNAL_MEMORY_CONTROLLER}, {"vic_floor", 0, NVHOST_MODULE_ID_CBUS_FLOOR}, {"emc_shared", 0, NVHOST_MODULE_ID_EMC_SHARED} }, .version = NVHOST_ENCODE_FLCN_VER(3, 0), .moduleid = NVHOST_MODULE_VIC, .class = NV_GRAPHICS_VIC_CLASS_ID, .can_powergate = true, .engine_can_cg = true, .engine_cg_regs = t12x_vic_gating_registers, .poweron_reset = true, .autosuspend_delay = 500, .finalize_poweron = nvhost_vic_finalize_poweron, .scaling_init = nvhost_scale_emc_init, .scaling_deinit = nvhost_scale_emc_deinit, .busy = nvhost_scale_notify_busy, .idle = nvhost_scale_notify_idle, .scaling_post_cb = &nvhost_scale_emc_callback, .devfreq_governor = "nvhost_podgov", .actmon_regs = HOST1X_CHANNEL_ACTMON2_REG_BASE, .actmon_enabled = true, .linear_emc = true, .push_work_done = true, .firmware_name = "vic03_ucode.bin", .aggregate_constraints = nvhost_vic_aggregate_constraints, .num_ppc = 2, .resource_policy = RESOURCE_PER_CHANNEL_INSTANCE, .serialize = true, }; #endif /* * T132 overrides for platform data. */ #if defined(CONFIG_TEGRA_GRHOST_NVENC) static struct nvhost_device_data t132_msenc_info = { .num_channels = 1, .devfs_name = "msenc", .version = NVHOST_ENCODE_FLCN_VER(3, 1), .modulemutexes = {NVMODMUTEX_MSENC}, .class = NV_VIDEO_ENCODE_MSENC_CLASS_ID, .clocks = {{"msenc", UINT_MAX, 0, TEGRA_MC_CLIENT_MSENC}, {"emc", HOST_EMC_FLOOR, NVHOST_MODULE_ID_EXTERNAL_MEMORY_CONTROLLER} }, .moduleid = NVHOST_MODULE_MSENC, .autosuspend_delay = 100, .can_powergate = true, .poweron_reset = true, .finalize_poweron = nvhost_flcn_finalize_poweron, .firmware_name = "nvhost_msenc031.fw", .resource_policy = RESOURCE_PER_CHANNEL_INSTANCE, .serialize = true, }; #endif static struct { struct nvhost_device_data *from; struct nvhost_device_data *to; } t132_override[] = { #if defined(CONFIG_TEGRA_GRHOST_NVENC) {&t124_msenc_info, &t132_msenc_info}, #endif }; #include "host1x/host1x_channel.c" static void t124_set_nvhost_chanops(struct nvhost_channel *ch) { if (ch) ch->ops = host1x_channel_ops; } int nvhost_init_t124_channel_support(struct nvhost_master *host, struct nvhost_chip_support *op) { op->nvhost_dev.set_nvhost_chanops = t124_set_nvhost_chanops; return 0; } static void t124_remove_support(struct nvhost_chip_support *op) { kfree(op->priv); op->priv = NULL; } #include "host1x/host1x_cdma.c" #include "host1x/host1x_debug.c" #include "host1x/host1x_syncpt.c" #include "host1x/host1x_intr.c" #if defined(CONFIG_TEGRA_GRHOST_SCALE) #include "host1x/host1x_actmon_t124.c" #endif int nvhost_init_t124_support(struct nvhost_master *host, struct nvhost_chip_support *op) { int i = 0; int err; struct t124 *t124 = NULL; struct nvhost_device_data *data = platform_get_drvdata(host->dev); /* Select the soc name */ if (tegra_get_chip_id() == TEGRA124) op->soc_name = "tegra12x"; else op->soc_name = "tegra13x"; /* don't worry about cleaning up on failure... "remove" does it. */ err = nvhost_init_t124_channel_support(host, op); if (err) return err; op->cdma = host1x_cdma_ops; op->push_buffer = host1x_pushbuffer_ops; op->debug = host1x_debug_ops; host->sync_aperture = host->aperture + HOST1X_CHANNEL_SYNC_REG_BASE; op->syncpt = host1x_syncpt_ops; op->intr = host1x_intr_ops; #if defined(CONFIG_TEGRA_GRHOST_SCALE) op->actmon = host1x_actmon_ops; #endif if (nvhost_dev_is_virtual(host->dev)) { data->can_powergate = false; vhost_init_host1x_syncpt_ops(&op->syncpt); vhost_init_host1x_intr_ops(&op->intr); vhost_init_host1x_cdma_ops(&op->cdma); vhost_init_host1x_debug_ops(&op->debug); } t124 = kzalloc(sizeof(struct t124), GFP_KERNEL); if (!t124) { err = -ENOMEM; goto err; } t124->host = host; op->priv = t124; op->remove_support = t124_remove_support; #if defined(CONFIG_ARCH_TEGRA_210_SOC) if (tegra_get_chip_id() == TEGRA132) { #else if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA13) { #endif for (i = 0; i < ARRAY_SIZE(t132_override); i++) { struct nvhost_device_data *from = t132_override[i].from; struct nvhost_device_data *to = t132_override[i].to; /* replace the platform data by t132 data */ *from = *to; } } return 0; err: kfree(t124); op->priv = NULL; op->remove_support = NULL; return err; }