cregit-Linux how code gets into the kernel

Release 4.12 drivers/gpu/drm/tegra/vic.c

/*
 * Copyright (c) 2015, NVIDIA Corporation.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/clk.h>
#include <linux/host1x.h>
#include <linux/iommu.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>

#include <soc/tegra/pmc.h>

#include "drm.h"
#include "falcon.h"
#include "vic.h"


struct vic_config {
	
const char *firmware;
};


struct vic {
	
struct falcon falcon;
	
bool booted;

	
void __iomem *regs;
	
struct tegra_drm_client client;
	
struct host1x_channel *channel;
	
struct iommu_domain *domain;
	
struct device *dev;
	
struct clk *clk;

	/* Platform configuration */
	
const struct vic_config *config;
};


static inline struct vic *to_vic(struct tegra_drm_client *client) { return container_of(client, struct vic, client); }

Contributors

PersonTokensPropCommitsCommitProp
Arto Merilainen25100.00%1100.00%
Total25100.00%1100.00%


static void vic_writel(struct vic *vic, u32 value, unsigned int offset) { writel(value, vic->regs + offset); }

Contributors

PersonTokensPropCommitsCommitProp
Arto Merilainen29100.00%1100.00%
Total29100.00%1100.00%


static int vic_runtime_resume(struct device *dev) { struct vic *vic = dev_get_drvdata(dev); return clk_prepare_enable(vic->clk); }

Contributors

PersonTokensPropCommitsCommitProp
Arto Merilainen29100.00%1100.00%
Total29100.00%1100.00%


static int vic_runtime_suspend(struct device *dev) { struct vic *vic = dev_get_drvdata(dev); clk_disable_unprepare(vic->clk); vic->booted = false; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Arto Merilainen37100.00%1100.00%
Total37100.00%1100.00%


static int vic_boot(struct vic *vic) { u32 fce_ucode_size, fce_bin_data_offset; void *hdr; int err = 0; if (vic->booted) return 0; /* setup clockgating registers */ vic_writel(vic, CG_IDLE_CG_DLY_CNT(4) | CG_IDLE_CG_EN | CG_WAKEUP_DLY_CNT(4), NV_PVIC_MISC_PRI_VIC_CG); err = falcon_boot(&vic->falcon); if (err < 0) return err; hdr = vic->falcon.firmware.vaddr; fce_bin_data_offset = *(u32 *)(hdr + VIC_UCODE_FCE_DATA_OFFSET); hdr = vic->falcon.firmware.vaddr + *(u32 *)(hdr + VIC_UCODE_FCE_HEADER_OFFSET); fce_ucode_size = *(u32 *)(hdr + FCE_UCODE_SIZE_OFFSET); falcon_execute_method(&vic->falcon, VIC_SET_APPLICATION_ID, 1); falcon_execute_method(&vic->falcon, VIC_SET_FCE_UCODE_SIZE, fce_ucode_size); falcon_execute_method(&vic->falcon, VIC_SET_FCE_UCODE_OFFSET, (vic->falcon.firmware.paddr + fce_bin_data_offset) >> 8); err = falcon_wait_idle(&vic->falcon); if (err < 0) { dev_err(vic->dev, "failed to set application ID and FCE base\n"); return err; } vic->booted = true; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Arto Merilainen217100.00%1100.00%
Total217100.00%1100.00%


static void *vic_falcon_alloc(struct falcon *falcon, size_t size, dma_addr_t *iova) { struct tegra_drm *tegra = falcon->data; return tegra_drm_alloc(tegra, size, iova); }

Contributors

PersonTokensPropCommitsCommitProp
Arto Merilainen38100.00%1100.00%
Total38100.00%1100.00%


static void vic_falcon_free(struct falcon *falcon, size_t size, dma_addr_t iova, void *va) { struct tegra_drm *tegra = falcon->data; return tegra_drm_free(tegra, size, va, iova); }

Contributors

PersonTokensPropCommitsCommitProp
Arto Merilainen42100.00%1100.00%
Total42100.00%1100.00%

static const struct falcon_ops vic_falcon_ops = { .alloc = vic_falcon_alloc, .free = vic_falcon_free };
static int vic_init(struct host1x_client *client) { struct tegra_drm_client *drm = host1x_to_drm_client(client); struct drm_device *dev = dev_get_drvdata(client->parent); struct tegra_drm *tegra = dev->dev_private; struct vic *vic = to_vic(drm); int err; if (tegra->domain) { err = iommu_attach_device(tegra->domain, vic->dev); if (err < 0) { dev_err(vic->dev, "failed to attach to domain: %d\n", err); return err; } vic->domain = tegra->domain; } if (!vic->falcon.data) { vic->falcon.data = tegra; err = falcon_load_firmware(&vic->falcon); if (err < 0) goto detach_device; } vic->channel = host1x_channel_request(client->dev); if (!vic->channel) { err = -ENOMEM; goto detach_device; } client->syncpts[0] = host1x_syncpt_request(client->dev, 0); if (!client->syncpts[0]) { err = -ENOMEM; goto free_channel; } err = tegra_drm_register_client(tegra, drm); if (err < 0) goto free_syncpt; return 0; free_syncpt: host1x_syncpt_free(client->syncpts[0]); free_channel: host1x_channel_free(vic->channel); detach_device: if (tegra->domain) iommu_detach_device(tegra->domain, vic->dev); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Arto Merilainen272100.00%1100.00%
Total272100.00%1100.00%


static int vic_exit(struct host1x_client *client) { struct tegra_drm_client *drm = host1x_to_drm_client(client); struct drm_device *dev = dev_get_drvdata(client->parent); struct tegra_drm *tegra = dev->dev_private; struct vic *vic = to_vic(drm); int err; err = tegra_drm_unregister_client(tegra, drm); if (err < 0) return err; host1x_syncpt_free(client->syncpts[0]); host1x_channel_free(vic->channel); if (vic->domain) { iommu_detach_device(vic->domain, vic->dev); vic->domain = NULL; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Arto Merilainen118100.00%1100.00%
Total118100.00%1100.00%

static const struct host1x_client_ops vic_client_ops = { .init = vic_init, .exit = vic_exit, };
static int vic_open_channel(struct tegra_drm_client *client, struct tegra_drm_context *context) { struct vic *vic = to_vic(client); int err; err = pm_runtime_get_sync(vic->dev); if (err < 0) return err; err = vic_boot(vic); if (err < 0) { pm_runtime_put(vic->dev); return err; } context->channel = host1x_channel_get(vic->channel); if (!context->channel) { pm_runtime_put(vic->dev); return -ENOMEM; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Arto Merilainen106100.00%1100.00%
Total106100.00%1100.00%


static void vic_close_channel(struct tegra_drm_context *context) { struct vic *vic = to_vic(context->client); host1x_channel_put(context->channel); pm_runtime_put(vic->dev); }

Contributors

PersonTokensPropCommitsCommitProp
Arto Merilainen37100.00%1100.00%
Total37100.00%1100.00%

static const struct tegra_drm_client_ops vic_ops = { .open_channel = vic_open_channel, .close_channel = vic_close_channel, .submit = tegra_drm_submit, }; static const struct vic_config vic_t124_config = { .firmware = "nvidia/tegra124/vic03_ucode.bin", }; static const struct vic_config vic_t210_config = { .firmware = "nvidia/tegra210/vic04_ucode.bin", }; static const struct of_device_id vic_match[] = { { .compatible = "nvidia,tegra124-vic", .data = &vic_t124_config }, { .compatible = "nvidia,tegra210-vic", .data = &vic_t210_config }, { }, };
static int vic_probe(struct platform_device *pdev) { struct vic_config *vic_config = NULL; struct device *dev = &pdev->dev; struct host1x_syncpt **syncpts; struct resource *regs; const struct of_device_id *match; struct vic *vic; int err; match = of_match_device(vic_match, dev); vic_config = (struct vic_config *)match->data; vic = devm_kzalloc(dev, sizeof(*vic), GFP_KERNEL); if (!vic) return -ENOMEM; syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL); if (!syncpts) return -ENOMEM; regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) { dev_err(&pdev->dev, "failed to get registers\n"); return -ENXIO; } vic->regs = devm_ioremap_resource(dev, regs); if (IS_ERR(vic->regs)) return PTR_ERR(vic->regs); vic->clk = devm_clk_get(dev, NULL); if (IS_ERR(vic->clk)) { dev_err(&pdev->dev, "failed to get clock\n"); return PTR_ERR(vic->clk); } vic->falcon.dev = dev; vic->falcon.regs = vic->regs; vic->falcon.ops = &vic_falcon_ops; err = falcon_init(&vic->falcon); if (err < 0) return err; err = falcon_read_firmware(&vic->falcon, vic_config->firmware); if (err < 0) goto exit_falcon; platform_set_drvdata(pdev, vic); INIT_LIST_HEAD(&vic->client.base.list); vic->client.base.ops = &vic_client_ops; vic->client.base.dev = dev; vic->client.base.class = HOST1X_CLASS_VIC; vic->client.base.syncpts = syncpts; vic->client.base.num_syncpts = 1; vic->dev = dev; vic->config = vic_config; INIT_LIST_HEAD(&vic->client.list); vic->client.ops = &vic_ops; err = host1x_client_register(&vic->client.base); if (err < 0) { dev_err(dev, "failed to register host1x client: %d\n", err); platform_set_drvdata(pdev, NULL); goto exit_falcon; } pm_runtime_enable(&pdev->dev); if (!pm_runtime_enabled(&pdev->dev)) { err = vic_runtime_resume(&pdev->dev); if (err < 0) goto unregister_client; } return 0; unregister_client: host1x_client_unregister(&vic->client.base); exit_falcon: falcon_exit(&vic->falcon); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Arto Merilainen498100.00%1100.00%
Total498100.00%1100.00%


static int vic_remove(struct platform_device *pdev) { struct vic *vic = platform_get_drvdata(pdev); int err; err = host1x_client_unregister(&vic->client.base); if (err < 0) { dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", err); return err; } if (pm_runtime_enabled(&pdev->dev)) pm_runtime_disable(&pdev->dev); else vic_runtime_suspend(&pdev->dev); falcon_exit(&vic->falcon); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Arto Merilainen97100.00%1100.00%
Total97100.00%1100.00%

static const struct dev_pm_ops vic_pm_ops = { SET_RUNTIME_PM_OPS(vic_runtime_suspend, vic_runtime_resume, NULL) }; struct platform_driver tegra_vic_driver = { .driver = { .name = "tegra-vic", .of_match_table = vic_match, .pm = &vic_pm_ops }, .probe = vic_probe, .remove = vic_remove, };

Overall Contributors

PersonTokensPropCommitsCommitProp
Arto Merilainen1822100.00%1100.00%
Total1822100.00%1100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.