Commit 29a1da27 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm/tegra/for-4.21-rc1' of git://anongit.freedesktop.org/tegra/linux into drm-next

drm/tegra: Changes for v4.21-rc1

These changes contain a couple of minor fixes for host1x and the Falcon
library in Tegra DRM. There are also a couple of missing pieces that
finally enable support for host1x, VIC and display on Tegra194. I've
also added a patch that enables audio over HDMI using the SOR which has
been tested, and works, on both Tegra186 and Tegra194.
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Thierry Reding <thierry.reding@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181207134712.32683-1-thierry.reding@gmail.com
parents e7df065a 180b46ec
......@@ -1978,6 +1978,23 @@ static irqreturn_t tegra_dc_irq(int irq, void *data)
return IRQ_HANDLED;
}
static bool tegra_dc_has_window_groups(struct tegra_dc *dc)
{
unsigned int i;
if (!dc->soc->wgrps)
return true;
for (i = 0; i < dc->soc->num_wgrps; i++) {
const struct tegra_windowgroup_soc *wgrp = &dc->soc->wgrps[i];
if (wgrp->dc == dc->pipe && wgrp->num_windows > 0)
return true;
}
return false;
}
static int tegra_dc_init(struct host1x_client *client)
{
struct drm_device *drm = dev_get_drvdata(client->parent);
......@@ -1993,22 +2010,8 @@ static int tegra_dc_init(struct host1x_client *client)
* assign a primary plane to them, which in turn will cause KMS to
* crash.
*/
if (dc->soc->wgrps) {
bool has_wgrps = false;
unsigned int i;
for (i = 0; i < dc->soc->num_wgrps; i++) {
const struct tegra_windowgroup_soc *wgrp = &dc->soc->wgrps[i];
if (wgrp->dc == dc->pipe && wgrp->num_windows > 0) {
has_wgrps = true;
break;
}
}
if (!has_wgrps)
return 0;
}
if (!tegra_dc_has_window_groups(dc))
return 0;
dc->syncpt = host1x_syncpt_request(client, flags);
if (!dc->syncpt)
......@@ -2094,6 +2097,9 @@ static int tegra_dc_exit(struct host1x_client *client)
struct tegra_dc *dc = host1x_client_to_dc(client);
int err;
if (!tegra_dc_has_window_groups(dc))
return 0;
devm_free_irq(dc->dev, dc->irq, dc);
err = tegra_dc_rgb_exit(dc);
......
......@@ -1274,6 +1274,7 @@ static const struct of_device_id host1x_drm_subdevs[] = {
{ .compatible = "nvidia,tegra194-display", },
{ .compatible = "nvidia,tegra194-dc", },
{ .compatible = "nvidia,tegra194-sor", },
{ .compatible = "nvidia,tegra194-vic", },
{ /* sentinel */ }
};
......
......@@ -141,9 +141,9 @@ int falcon_load_firmware(struct falcon *falcon)
/* allocate iova space for the firmware */
falcon->firmware.vaddr = falcon->ops->alloc(falcon, firmware->size,
&falcon->firmware.paddr);
if (!falcon->firmware.vaddr) {
dev_err(falcon->dev, "dma memory mapping failed\n");
return -ENOMEM;
if (IS_ERR(falcon->firmware.vaddr)) {
dev_err(falcon->dev, "DMA memory mapping failed\n");
return PTR_ERR(falcon->firmware.vaddr);
}
/* copy firmware image into local area. this also ensures endianness */
......@@ -197,11 +197,19 @@ void falcon_exit(struct falcon *falcon)
int falcon_boot(struct falcon *falcon)
{
unsigned long offset;
u32 value;
int err;
if (!falcon->firmware.vaddr)
return -EINVAL;
err = readl_poll_timeout(falcon->regs + FALCON_DMACTL, value,
(value & (FALCON_DMACTL_IMEM_SCRUBBING |
FALCON_DMACTL_DMEM_SCRUBBING)) == 0,
10, 10000);
if (err < 0)
return err;
falcon_writel(falcon, 0, FALCON_DMACTL);
/* setup the address of the binary data so Falcon can access it later */
......
......@@ -742,7 +742,9 @@ static const struct host1x_client_ops tegra_display_hub_ops = {
static int tegra_display_hub_probe(struct platform_device *pdev)
{
struct device_node *child = NULL;
struct tegra_display_hub *hub;
struct clk *clk;
unsigned int i;
int err;
......@@ -801,6 +803,34 @@ static int tegra_display_hub_probe(struct platform_device *pdev)
return err;
}
hub->num_heads = of_get_child_count(pdev->dev.of_node);
hub->clk_heads = devm_kcalloc(&pdev->dev, hub->num_heads, sizeof(clk),
GFP_KERNEL);
if (!hub->clk_heads)
return -ENOMEM;
for (i = 0; i < hub->num_heads; i++) {
child = of_get_next_child(pdev->dev.of_node, child);
if (!child) {
dev_err(&pdev->dev, "failed to find node for head %u\n",
i);
return -ENODEV;
}
clk = devm_get_clk_from_child(&pdev->dev, child, "dc");
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "failed to get clock for head %u\n",
i);
of_node_put(child);
return PTR_ERR(clk);
}
hub->clk_heads[i] = clk;
}
of_node_put(child);
/* XXX: enable clock across reset? */
err = reset_control_assert(hub->rst);
if (err < 0)
......@@ -840,12 +870,16 @@ static int tegra_display_hub_remove(struct platform_device *pdev)
static int __maybe_unused tegra_display_hub_suspend(struct device *dev)
{
struct tegra_display_hub *hub = dev_get_drvdata(dev);
unsigned int i = hub->num_heads;
int err;
err = reset_control_assert(hub->rst);
if (err < 0)
return err;
while (i--)
clk_disable_unprepare(hub->clk_heads[i]);
clk_disable_unprepare(hub->clk_hub);
clk_disable_unprepare(hub->clk_dsc);
clk_disable_unprepare(hub->clk_disp);
......@@ -856,6 +890,7 @@ static int __maybe_unused tegra_display_hub_suspend(struct device *dev)
static int __maybe_unused tegra_display_hub_resume(struct device *dev)
{
struct tegra_display_hub *hub = dev_get_drvdata(dev);
unsigned int i;
int err;
err = clk_prepare_enable(hub->clk_disp);
......@@ -870,13 +905,22 @@ static int __maybe_unused tegra_display_hub_resume(struct device *dev)
if (err < 0)
goto disable_dsc;
for (i = 0; i < hub->num_heads; i++) {
err = clk_prepare_enable(hub->clk_heads[i]);
if (err < 0)
goto disable_heads;
}
err = reset_control_deassert(hub->rst);
if (err < 0)
goto disable_hub;
goto disable_heads;
return 0;
disable_hub:
disable_heads:
while (i--)
clk_disable_unprepare(hub->clk_heads[i]);
clk_disable_unprepare(hub->clk_hub);
disable_dsc:
clk_disable_unprepare(hub->clk_dsc);
......
......@@ -49,6 +49,9 @@ struct tegra_display_hub {
struct clk *clk_hub;
struct reset_control *rst;
unsigned int num_heads;
struct clk **clk_heads;
const struct tegra_display_hub_soc *soc;
struct tegra_windowgroup *wgrps;
};
......
......@@ -19,6 +19,8 @@
#include <soc/tegra/pmc.h>
#include <sound/hda_verbs.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_panel.h>
......@@ -29,14 +31,6 @@
#include "sor.h"
#include "trace.h"
/*
* XXX Remove this after the commit adding it to soc/tegra/pmc.h has been
* merged. Having this around after the commit is merged should be safe since
* the preprocessor will effectively replace all occurrences and therefore no
* duplicate will be defined.
*/
#define TEGRA_IO_PAD_HDMI_DP0 26
#define SOR_REKEY 0x38
struct tegra_sor_hdmi_settings {
......@@ -407,6 +401,7 @@ struct tegra_sor {
const struct tegra_sor_soc *soc;
void __iomem *regs;
unsigned int index;
unsigned int irq;
struct reset_control *rst;
struct clk *clk_parent;
......@@ -433,6 +428,11 @@ struct tegra_sor {
struct delayed_work scdc;
bool scdc_enabled;
struct {
unsigned int sample_rate;
unsigned int channels;
} audio;
};
struct tegra_sor_state {
......@@ -2139,6 +2139,144 @@ tegra_sor_hdmi_setup_avi_infoframe(struct tegra_sor *sor,
return 0;
}
static void tegra_sor_write_eld(struct tegra_sor *sor)
{
size_t length = drm_eld_size(sor->output.connector.eld), i;
for (i = 0; i < length; i++)
tegra_sor_writel(sor, i << 8 | sor->output.connector.eld[i],
SOR_AUDIO_HDA_ELD_BUFWR);
/*
* The HDA codec will always report an ELD buffer size of 96 bytes and
* the HDA codec driver will check that each byte read from the buffer
* is valid. Therefore every byte must be written, even if no 96 bytes
* were parsed from EDID.
*/
for (i = length; i < 96; i++)
tegra_sor_writel(sor, i << 8 | 0, SOR_AUDIO_HDA_ELD_BUFWR);
}
static void tegra_sor_audio_prepare(struct tegra_sor *sor)
{
u32 value;
tegra_sor_write_eld(sor);
value = SOR_AUDIO_HDA_PRESENSE_ELDV | SOR_AUDIO_HDA_PRESENSE_PD;
tegra_sor_writel(sor, value, SOR_AUDIO_HDA_PRESENSE);
}
static void tegra_sor_audio_unprepare(struct tegra_sor *sor)
{
tegra_sor_writel(sor, 0, SOR_AUDIO_HDA_PRESENSE);
}
static int tegra_sor_hdmi_enable_audio_infoframe(struct tegra_sor *sor)
{
u8 buffer[HDMI_INFOFRAME_SIZE(AUDIO)];
struct hdmi_audio_infoframe frame;
u32 value;
int err;
err = hdmi_audio_infoframe_init(&frame);
if (err < 0) {
dev_err(sor->dev, "failed to setup audio infoframe: %d\n", err);
return err;
}
frame.channels = sor->audio.channels;
err = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
if (err < 0) {
dev_err(sor->dev, "failed to pack audio infoframe: %d\n", err);
return err;
}
tegra_sor_hdmi_write_infopack(sor, buffer, err);
value = tegra_sor_readl(sor, SOR_HDMI_AUDIO_INFOFRAME_CTRL);
value |= INFOFRAME_CTRL_CHECKSUM_ENABLE;
value |= INFOFRAME_CTRL_ENABLE;
tegra_sor_writel(sor, value, SOR_HDMI_AUDIO_INFOFRAME_CTRL);
return 0;
}
static void tegra_sor_hdmi_audio_enable(struct tegra_sor *sor)
{
u32 value;
value = tegra_sor_readl(sor, SOR_AUDIO_CNTRL);
/* select HDA audio input */
value &= ~SOR_AUDIO_CNTRL_SOURCE_SELECT(SOURCE_SELECT_MASK);
value |= SOR_AUDIO_CNTRL_SOURCE_SELECT(SOURCE_SELECT_HDA);
/* inject null samples */
if (sor->audio.channels != 2)
value &= ~SOR_AUDIO_CNTRL_INJECT_NULLSMPL;
else
value |= SOR_AUDIO_CNTRL_INJECT_NULLSMPL;
value |= SOR_AUDIO_CNTRL_AFIFO_FLUSH;
tegra_sor_writel(sor, value, SOR_AUDIO_CNTRL);
/* enable advertising HBR capability */
tegra_sor_writel(sor, SOR_AUDIO_SPARE_HBR_ENABLE, SOR_AUDIO_SPARE);
tegra_sor_writel(sor, 0, SOR_HDMI_ACR_CTRL);
value = SOR_HDMI_SPARE_ACR_PRIORITY_HIGH |
SOR_HDMI_SPARE_CTS_RESET(1) |
SOR_HDMI_SPARE_HW_CTS_ENABLE;
tegra_sor_writel(sor, value, SOR_HDMI_SPARE);
/* enable HW CTS */
value = SOR_HDMI_ACR_SUBPACK_LOW_SB1(0);
tegra_sor_writel(sor, value, SOR_HDMI_ACR_0441_SUBPACK_LOW);
/* allow packet to be sent */
value = SOR_HDMI_ACR_SUBPACK_HIGH_ENABLE;
tegra_sor_writel(sor, value, SOR_HDMI_ACR_0441_SUBPACK_HIGH);
/* reset N counter and enable lookup */
value = SOR_HDMI_AUDIO_N_RESET | SOR_HDMI_AUDIO_N_LOOKUP;
tegra_sor_writel(sor, value, SOR_HDMI_AUDIO_N);
value = (24000 * 4096) / (128 * sor->audio.sample_rate / 1000);
tegra_sor_writel(sor, value, SOR_AUDIO_AVAL_0320);
tegra_sor_writel(sor, 4096, SOR_AUDIO_NVAL_0320);
tegra_sor_writel(sor, 20000, SOR_AUDIO_AVAL_0441);
tegra_sor_writel(sor, 4704, SOR_AUDIO_NVAL_0441);
tegra_sor_writel(sor, 20000, SOR_AUDIO_AVAL_0882);
tegra_sor_writel(sor, 9408, SOR_AUDIO_NVAL_0882);
tegra_sor_writel(sor, 20000, SOR_AUDIO_AVAL_1764);
tegra_sor_writel(sor, 18816, SOR_AUDIO_NVAL_1764);
value = (24000 * 6144) / (128 * sor->audio.sample_rate / 1000);
tegra_sor_writel(sor, value, SOR_AUDIO_AVAL_0480);
tegra_sor_writel(sor, 6144, SOR_AUDIO_NVAL_0480);
value = (24000 * 12288) / (128 * sor->audio.sample_rate / 1000);
tegra_sor_writel(sor, value, SOR_AUDIO_AVAL_0960);
tegra_sor_writel(sor, 12288, SOR_AUDIO_NVAL_0960);
value = (24000 * 24576) / (128 * sor->audio.sample_rate / 1000);
tegra_sor_writel(sor, value, SOR_AUDIO_AVAL_1920);
tegra_sor_writel(sor, 24576, SOR_AUDIO_NVAL_1920);
value = tegra_sor_readl(sor, SOR_HDMI_AUDIO_N);
value &= ~SOR_HDMI_AUDIO_N_RESET;
tegra_sor_writel(sor, value, SOR_HDMI_AUDIO_N);
tegra_sor_hdmi_enable_audio_infoframe(sor);
}
static void tegra_sor_hdmi_disable_audio_infoframe(struct tegra_sor *sor)
{
u32 value;
......@@ -2148,6 +2286,11 @@ static void tegra_sor_hdmi_disable_audio_infoframe(struct tegra_sor *sor)
tegra_sor_writel(sor, value, SOR_HDMI_AUDIO_INFOFRAME_CTRL);
}
static void tegra_sor_hdmi_audio_disable(struct tegra_sor *sor)
{
tegra_sor_hdmi_disable_audio_infoframe(sor);
}
static struct tegra_sor_hdmi_settings *
tegra_sor_hdmi_find_settings(struct tegra_sor *sor, unsigned long frequency)
{
......@@ -2243,6 +2386,7 @@ static void tegra_sor_hdmi_disable(struct drm_encoder *encoder)
u32 value;
int err;
tegra_sor_audio_unprepare(sor);
tegra_sor_hdmi_scdc_stop(sor);
err = tegra_sor_detach(sor);
......@@ -2651,6 +2795,7 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder)
dev_err(sor->dev, "failed to wakeup SOR: %d\n", err);
tegra_sor_hdmi_scdc_start(sor);
tegra_sor_audio_prepare(sor);
}
static const struct drm_encoder_helper_funcs tegra_sor_hdmi_helpers = {
......@@ -2666,6 +2811,7 @@ static int tegra_sor_init(struct host1x_client *client)
struct tegra_sor *sor = host1x_client_to_sor(client);
int connector = DRM_MODE_CONNECTOR_Unknown;
int encoder = DRM_MODE_ENCODER_NONE;
u32 value;
int err;
if (!sor->aux) {
......@@ -2759,6 +2905,15 @@ static int tegra_sor_init(struct host1x_client *client)
if (err < 0)
return err;
/*
* Enable and unmask the HDA codec SCRATCH0 register interrupt. This
* is used for interoperability between the HDA codec driver and the
* HDMI/DP driver.
*/
value = SOR_INT_CODEC_SCRATCH1 | SOR_INT_CODEC_SCRATCH0;
tegra_sor_writel(sor, value, SOR_INT_ENABLE);
tegra_sor_writel(sor, value, SOR_INT_MASK);
return 0;
}
......@@ -2767,6 +2922,9 @@ static int tegra_sor_exit(struct host1x_client *client)
struct tegra_sor *sor = host1x_client_to_sor(client);
int err;
tegra_sor_writel(sor, 0, SOR_INT_MASK);
tegra_sor_writel(sor, 0, SOR_INT_ENABLE);
tegra_output_exit(&sor->output);
if (sor->aux) {
......@@ -3037,6 +3195,54 @@ static int tegra_sor_parse_dt(struct tegra_sor *sor)
return 0;
}
static void tegra_hda_parse_format(unsigned int format, unsigned int *rate,
unsigned int *channels)
{
unsigned int mul, div;
if (format & AC_FMT_BASE_44K)
*rate = 44100;
else
*rate = 48000;
mul = (format & AC_FMT_MULT_MASK) >> AC_FMT_MULT_SHIFT;
div = (format & AC_FMT_DIV_MASK) >> AC_FMT_DIV_SHIFT;
*rate = *rate * (mul + 1) / (div + 1);
*channels = (format & AC_FMT_CHAN_MASK) >> AC_FMT_CHAN_SHIFT;
}
static irqreturn_t tegra_sor_irq(int irq, void *data)
{
struct tegra_sor *sor = data;
u32 value;
value = tegra_sor_readl(sor, SOR_INT_STATUS);
tegra_sor_writel(sor, value, SOR_INT_STATUS);
if (value & SOR_INT_CODEC_SCRATCH0) {
value = tegra_sor_readl(sor, SOR_AUDIO_HDA_CODEC_SCRATCH0);
if (value & SOR_AUDIO_HDA_CODEC_SCRATCH0_VALID) {
unsigned int format, sample_rate, channels;
format = value & SOR_AUDIO_HDA_CODEC_SCRATCH0_FMT_MASK;
tegra_hda_parse_format(format, &sample_rate, &channels);
sor->audio.sample_rate = sample_rate;
sor->audio.channels = channels;
tegra_sor_hdmi_audio_enable(sor);
} else {
tegra_sor_hdmi_audio_disable(sor);
}
}
return IRQ_HANDLED;
}
static int tegra_sor_probe(struct platform_device *pdev)
{
struct device_node *np;
......@@ -3119,14 +3325,38 @@ static int tegra_sor_probe(struct platform_device *pdev)
goto remove;
}
if (!pdev->dev.pm_domain) {
sor->rst = devm_reset_control_get(&pdev->dev, "sor");
if (IS_ERR(sor->rst)) {
err = PTR_ERR(sor->rst);
err = platform_get_irq(pdev, 0);
if (err < 0) {
dev_err(&pdev->dev, "failed to get IRQ: %d\n", err);
goto remove;
}
sor->irq = err;
err = devm_request_irq(sor->dev, sor->irq, tegra_sor_irq, 0,
dev_name(sor->dev), sor);
if (err < 0) {
dev_err(&pdev->dev, "failed to request IRQ: %d\n", err);
goto remove;
}
sor->rst = devm_reset_control_get(&pdev->dev, "sor");
if (IS_ERR(sor->rst)) {
err = PTR_ERR(sor->rst);
if (err != -EBUSY || WARN_ON(!pdev->dev.pm_domain)) {
dev_err(&pdev->dev, "failed to get reset control: %d\n",
err);
goto remove;
}
/*
* At this point, the reset control is most likely being used
* by the generic power domain implementation. With any luck
* the power domain will have taken care of resetting the SOR
* and we don't have to do anything.
*/
sor->rst = NULL;
}
sor->clk = devm_clk_get(&pdev->dev, NULL);
......
......@@ -364,12 +364,28 @@
#define INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) << 8)
#define INFOFRAME_HEADER_TYPE(x) (((x) & 0xff) << 0)
#define SOR_HDMI_ACR_CTRL 0xb1
#define SOR_HDMI_ACR_0320_SUBPACK_LOW 0xb2
#define SOR_HDMI_ACR_SUBPACK_LOW_SB1(x) (((x) & 0xff) << 24)
#define SOR_HDMI_ACR_0320_SUBPACK_HIGH 0xb3
#define SOR_HDMI_ACR_SUBPACK_HIGH_ENABLE (1 << 31)
#define SOR_HDMI_ACR_0441_SUBPACK_LOW 0xb4
#define SOR_HDMI_ACR_0441_SUBPACK_HIGH 0xb5
#define SOR_HDMI_CTRL 0xc0
#define SOR_HDMI_CTRL_ENABLE (1 << 30)
#define SOR_HDMI_CTRL_MAX_AC_PACKET(x) (((x) & 0x1f) << 16)
#define SOR_HDMI_CTRL_AUDIO_LAYOUT (1 << 10)
#define SOR_HDMI_CTRL_REKEY(x) (((x) & 0x7f) << 0)
#define SOR_HDMI_SPARE 0xcb
#define SOR_HDMI_SPARE_ACR_PRIORITY_HIGH (1 << 31)
#define SOR_HDMI_SPARE_CTS_RESET(x) (((x) & 0x7) << 16)
#define SOR_HDMI_SPARE_HW_CTS_ENABLE (1 << 0)
#define SOR_REFCLK 0xe6
#define SOR_REFCLK_DIV_INT(x) ((((x) >> 2) & 0xff) << 8)
#define SOR_REFCLK_DIV_FRAC(x) (((x) & 0x3) << 6)
......@@ -378,10 +394,62 @@
#define SOR_INPUT_CONTROL_ARM_VIDEO_RANGE_LIMITED (1 << 1)
#define SOR_INPUT_CONTROL_HDMI_SRC_SELECT(x) (((x) & 0x1) << 0)
#define SOR_AUDIO_CNTRL 0xfc
#define SOR_AUDIO_CNTRL_INJECT_NULLSMPL (1 << 29)
#define SOR_AUDIO_CNTRL_SOURCE_SELECT(x) (((x) & 0x3) << 20)
#define SOURCE_SELECT_MASK 0x3
#define SOURCE_SELECT_HDA 0x2
#define SOURCE_SELECT_SPDIF 0x1
#define SOURCE_SELECT_AUTO 0x0
#define SOR_AUDIO_CNTRL_AFIFO_FLUSH (1 << 12)
#define SOR_AUDIO_SPARE 0xfe
#define SOR_AUDIO_SPARE_HBR_ENABLE (1 << 27)
#define SOR_AUDIO_NVAL_0320 0xff
#define SOR_AUDIO_NVAL_0441 0x100
#define SOR_AUDIO_NVAL_0882 0x101
#define SOR_AUDIO_NVAL_1764 0x102
#define SOR_AUDIO_NVAL_0480 0x103
#define SOR_AUDIO_NVAL_0960 0x104
#define SOR_AUDIO_NVAL_1920 0x105
#define SOR_AUDIO_HDA_CODEC_SCRATCH0 0x10a
#define SOR_AUDIO_HDA_CODEC_SCRATCH0_VALID (1 << 30)
#define SOR_AUDIO_HDA_CODEC_SCRATCH0_FMT_MASK 0xffff
#define SOR_AUDIO_HDA_ELD_BUFWR 0x10c
#define SOR_AUDIO_HDA_ELD_BUFWR_INDEX(x) (((x) & 0xff) << 8)
#define SOR_AUDIO_HDA_ELD_BUFWR_DATA(x) (((x) & 0xff) << 0)
#define SOR_AUDIO_HDA_PRESENSE 0x10d
#define SOR_AUDIO_HDA_PRESENSE_ELDV (1 << 1)
#define SOR_AUDIO_HDA_PRESENSE_PD (1 << 0)
#define SOR_AUDIO_AVAL_0320 0x10f
#define SOR_AUDIO_AVAL_0441 0x110
#define SOR_AUDIO_AVAL_0882 0x111
#define SOR_AUDIO_AVAL_1764 0x112
#define SOR_AUDIO_AVAL_0480 0x113
#define SOR_AUDIO_AVAL_0960 0x114
#define SOR_AUDIO_AVAL_1920 0x115
#define SOR_INT_STATUS 0x11c
#define SOR_INT_CODEC_CP_REQUEST (1 << 2)
#define SOR_INT_CODEC_SCRATCH1 (1 << 1)
#define SOR_INT_CODEC_SCRATCH0 (1 << 0)
#define SOR_INT_MASK 0x11d
#define SOR_INT_ENABLE 0x11e
#define SOR_HDMI_VSI_INFOFRAME_CTRL 0x123
#define SOR_HDMI_VSI_INFOFRAME_STATUS 0x124
#define SOR_HDMI_VSI_INFOFRAME_HEADER 0x125
#define SOR_HDMI_AUDIO_N 0x13c
#define SOR_HDMI_AUDIO_N_LOOKUP (1 << 28)
#define SOR_HDMI_AUDIO_N_RESET (1 << 20)
#define SOR_HDMI2_CTRL 0x13e
#define SOR_HDMI2_CTRL_CLOCK_MODE_DIV_BY_4 (1 << 1)
#define SOR_HDMI2_CTRL_SCRAMBLE (1 << 0)
......
......@@ -38,6 +38,7 @@ struct vic {
struct iommu_domain *domain;
struct device *dev;
struct clk *clk;
struct reset_control *rst;
/* Platform configuration */
const struct vic_config *config;
......@@ -56,13 +57,37 @@ static void vic_writel(struct vic *vic, u32 value, unsigned int offset)
static int vic_runtime_resume(struct device *dev)
{
struct vic *vic = dev_get_drvdata(dev);
int err;
err = clk_prepare_enable(vic->clk);
if (err < 0)
return err;
usleep_range(10, 20);
err = reset_control_deassert(vic->rst);
if (err < 0)
goto disable;
usleep_range(10, 20);
return 0;
return clk_prepare_enable(vic->clk);
disable:
clk_disable_unprepare(vic->clk);
return err;
}
static int vic_runtime_suspend(struct device *dev)
{
struct vic *vic = dev_get_drvdata(dev);
int err;
err = reset_control_assert(vic->rst);
if (err < 0)
return err;
usleep_range(2000, 4000);
clk_disable_unprepare(vic->clk);
......@@ -282,10 +307,18 @@ static const struct vic_config vic_t186_config = {
.version = 0x18,
};
#define NVIDIA_TEGRA_194_VIC_FIRMWARE "nvidia/tegra194/vic.bin"
static const struct vic_config vic_t194_config = {
.firmware = NVIDIA_TEGRA_194_VIC_FIRMWARE,
.version = 0x19,
};
static const struct of_device_id vic_match[] = {
{ .compatible = "nvidia,tegra124-vic", .data = &vic_t124_config },
{ .compatible = "nvidia,tegra210-vic", .data = &vic_t210_config },
{ .compatible = "nvidia,tegra186-vic", .data = &vic_t186_config },
{ .compatible = "nvidia,tegra194-vic", .data = &vic_t194_config },
{ },
};
......@@ -323,6 +356,14 @@ static int vic_probe(struct platform_device *pdev)
return PTR_ERR(vic->clk);
}
if (!dev->pm_domain) {
vic->rst = devm_reset_control_get(dev, "vic");
if (IS_ERR(vic->rst)) {
dev_err(&pdev->dev, "failed to get reset\n");
return PTR_ERR(vic->rst);
}
}
vic->falcon.dev = dev;
vic->falcon.regs = vic->regs;
vic->falcon.ops = &vic_falcon_ops;
......@@ -418,3 +459,6 @@ MODULE_FIRMWARE(NVIDIA_TEGRA_210_VIC_FIRMWARE);
#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC)
MODULE_FIRMWARE(NVIDIA_TEGRA_186_VIC_FIRMWARE);
#endif
#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
MODULE_FIRMWARE(NVIDIA_TEGRA_194_VIC_FIRMWARE);
#endif
......@@ -13,6 +13,7 @@ host1x-y = \
hw/host1x02.o \
hw/host1x04.o \
hw/host1x05.o \
hw/host1x06.o
hw/host1x06.o \
hw/host1x07.o
obj-$(CONFIG_TEGRA_HOST1X) += host1x.o
......@@ -44,6 +44,7 @@
#include "hw/host1x04.h"
#include "hw/host1x05.h"
#include "hw/host1x06.h"
#include "hw/host1x07.h"
void host1x_hypervisor_writel(struct host1x *host1x, u32 v, u32 r)
{
......@@ -130,7 +131,19 @@ static const struct host1x_info host1x06_info = {
.has_hypervisor = true,
};
static const struct host1x_info host1x07_info = {
.nb_channels = 63,
.nb_pts = 704,
.nb_mlocks = 32,
.nb_bases = 0,
.init = host1x07_init,
.sync_offset = 0x0,
.dma_mask = DMA_BIT_MASK(40),
.has_hypervisor = true,
};
static const struct of_device_id host1x_of_match[] = {
{ .compatible = "nvidia,tegra194-host1x", .data = &host1x07_info, },
{ .compatible = "nvidia,tegra186-host1x", .data = &host1x06_info, },
{ .compatible = "nvidia,tegra210-host1x", .data = &host1x05_info, },
{ .compatible = "nvidia,tegra124-host1x", .data = &host1x04_info, },
......
......@@ -26,7 +26,6 @@
#include "../intr.h"
#include "../job.h"
#define HOST1X_CHANNEL_SIZE 16384
#define TRACE_MAX_LENGTH 128U
static void trace_write_gather(struct host1x_cdma *cdma, struct host1x_bo *bo,
......@@ -203,7 +202,11 @@ static void enable_gather_filter(struct host1x *host,
static int host1x_channel_init(struct host1x_channel *ch, struct host1x *dev,
unsigned int index)
{
ch->regs = dev->regs + index * HOST1X_CHANNEL_SIZE;
#if HOST1X_HW < 6
ch->regs = dev->regs + index * 0x4000;
#else
ch->regs = dev->regs + index * 0x100;
#endif
enable_gather_filter(dev, ch);
return 0;
}
......
......@@ -62,9 +62,12 @@ static void host1x_debug_show_channel_fifo(struct host1x *host,
struct host1x_channel *ch,
struct output *o)
{
u32 val, rd_ptr, wr_ptr, start, end;
#if HOST1X_HW <= 6
u32 rd_ptr, wr_ptr, start, end;
u32 payload = INVALID_PAYLOAD;
unsigned int data_count = 0;
#endif
u32 val;
host1x_debug_output(o, "%u: fifo:\n", ch->id);
......@@ -78,6 +81,7 @@ static void host1x_debug_show_channel_fifo(struct host1x *host,
val = host1x_ch_readl(ch, HOST1X_CHANNEL_CMDFIFO_RDATA);
host1x_debug_output(o, "CMDFIFO_RDATA %08x\n", val);
#if HOST1X_HW <= 6
/* Peek pointer values are invalid during SLCG, so disable it */
host1x_hypervisor_writel(host, 0x1, HOST1X_HV_ICG_EN_OVERRIDE);
......@@ -127,6 +131,7 @@ static void host1x_debug_show_channel_fifo(struct host1x *host,
host1x_hypervisor_writel(host, 0x0, HOST1X_HV_CMDFIFO_PEEK_CTRL);
host1x_hypervisor_writel(host, 0x0, HOST1X_HV_ICG_EN_OVERRIDE);
#endif
}
static void host1x_debug_show_mlocks(struct host1x *host, struct output *o)
......
/*
* Host1x init for Tegra194 SoCs
*
* Copyright (c) 2018 NVIDIA Corporation.
*
* 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 <http://www.gnu.org/licenses/>.
*/
/* include hw specification */
#include "host1x07.h"
#include "host1x07_hardware.h"
/* include code */
#define HOST1X_HW 7
#include "cdma_hw.c"
#include "channel_hw.c"
#include "debug_hw.c"
#include "intr_hw.c"
#include "syncpt_hw.c"
#include "../dev.h"
int host1x07_init(struct host1x *host)
{
host->channel_op = &host1x_channel_ops;
host->cdma_op = &host1x_cdma_ops;
host->cdma_pb_op = &host1x_pushbuffer_ops;
host->syncpt_op = &host1x_syncpt_ops;
host->intr_op = &host1x_intr_ops;
host->debug_op = &host1x_debug_ops;
return 0;
}
/*
* Host1x init for Tegra194 SoCs
*
* Copyright (c) 2018 NVIDIA Corporation.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef HOST1X_HOST1X07_H
#define HOST1X_HOST1X07_H
struct host1x;
int host1x07_init(struct host1x *host);
#endif
/*
* Tegra host1x Register Offsets for Tegra194
*
* Copyright (c) 2018 NVIDIA Corporation.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef __HOST1X_HOST1X07_HARDWARE_H
#define __HOST1X_HOST1X07_HARDWARE_H
#include <linux/types.h>
#include <linux/bitops.h>
#include "hw_host1x07_uclass.h"
#include "hw_host1x07_vm.h"
#include "hw_host1x07_hypervisor.h"
static inline u32 host1x_class_host_wait_syncpt(
unsigned indx, unsigned threshold)
{
return host1x_uclass_wait_syncpt_indx_f(indx)
| host1x_uclass_wait_syncpt_thresh_f(threshold);
}
static inline u32 host1x_class_host_load_syncpt_base(
unsigned indx, unsigned threshold)
{
return host1x_uclass_load_syncpt_base_base_indx_f(indx)
| host1x_uclass_load_syncpt_base_value_f(threshold);
}
static inline u32 host1x_class_host_wait_syncpt_base(
unsigned indx, unsigned base_indx, unsigned offset)
{
return host1x_uclass_wait_syncpt_base_indx_f(indx)
| host1x_uclass_wait_syncpt_base_base_indx_f(base_indx)
| host1x_uclass_wait_syncpt_base_offset_f(offset);
}
static inline u32 host1x_class_host_incr_syncpt_base(
unsigned base_indx, unsigned offset)
{
return host1x_uclass_incr_syncpt_base_base_indx_f(base_indx)
| host1x_uclass_incr_syncpt_base_offset_f(offset);
}
static inline u32 host1x_class_host_incr_syncpt(
unsigned cond, unsigned indx)
{
return host1x_uclass_incr_syncpt_cond_f(cond)
| host1x_uclass_incr_syncpt_indx_f(indx);
}
static inline u32 host1x_class_host_indoff_reg_write(
unsigned mod_id, unsigned offset, bool auto_inc)
{
u32 v = host1x_uclass_indoff_indbe_f(0xf)
| host1x_uclass_indoff_indmodid_f(mod_id)
| host1x_uclass_indoff_indroffset_f(offset);
if (auto_inc)
v |= host1x_uclass_indoff_autoinc_f(1);
return v;
}
static inline u32 host1x_class_host_indoff_reg_read(
unsigned mod_id, unsigned offset, bool auto_inc)
{
u32 v = host1x_uclass_indoff_indmodid_f(mod_id)
| host1x_uclass_indoff_indroffset_f(offset)
| host1x_uclass_indoff_rwn_read_v();
if (auto_inc)
v |= host1x_uclass_indoff_autoinc_f(1);
return v;
}
/* cdma opcodes */
static inline u32 host1x_opcode_setclass(
unsigned class_id, unsigned offset, unsigned mask)
{
return (0 << 28) | (offset << 16) | (class_id << 6) | mask;
}
static inline u32 host1x_opcode_incr(unsigned offset, unsigned count)
{
return (1 << 28) | (offset << 16) | count;
}
static inline u32 host1x_opcode_nonincr(unsigned offset, unsigned count)
{
return (2 << 28) | (offset << 16) | count;
}
static inline u32 host1x_opcode_mask(unsigned offset, unsigned mask)
{
return (3 << 28) | (offset << 16) | mask;
}
static inline u32 host1x_opcode_imm(unsigned offset, unsigned value)
{
return (4 << 28) | (offset << 16) | value;
}
static inline u32 host1x_opcode_imm_incr_syncpt(unsigned cond, unsigned indx)
{
return host1x_opcode_imm(host1x_uclass_incr_syncpt_r(),
host1x_class_host_incr_syncpt(cond, indx));
}
static inline u32 host1x_opcode_restart(unsigned address)
{
return (5 << 28) | (address >> 4);
}
static inline u32 host1x_opcode_gather(unsigned count)
{
return (6 << 28) | count;
}
static inline u32 host1x_opcode_gather_nonincr(unsigned offset, unsigned count)
{
return (6 << 28) | (offset << 16) | BIT(15) | count;
}
static inline u32 host1x_opcode_gather_incr(unsigned offset, unsigned count)
{
return (6 << 28) | (offset << 16) | BIT(15) | BIT(14) | count;
}
#define HOST1X_OPCODE_NOP host1x_opcode_nonincr(0, 0)
#endif
......@@ -59,7 +59,7 @@ static inline u32 host1x_uclass_incr_syncpt_r(void)
host1x_uclass_incr_syncpt_r()
static inline u32 host1x_uclass_incr_syncpt_cond_f(u32 v)
{
return (v & 0xff) << 8;
return (v & 0xff) << 10;
}
#define HOST1X_UCLASS_INCR_SYNCPT_COND_F(v) \
host1x_uclass_incr_syncpt_cond_f(v)
......
/*
* Copyright (c) 2018 NVIDIA Corporation.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#define HOST1X_HV_SYNCPT_PROT_EN 0x1ac4
#define HOST1X_HV_SYNCPT_PROT_EN_CH_EN BIT(1)
#define HOST1X_HV_CH_KERNEL_FILTER_GBUFFER(x) (0x2020 + (x * 4))
#define HOST1X_HV_CMDFIFO_PEEK_CTRL 0x233c
#define HOST1X_HV_CMDFIFO_PEEK_CTRL_ADDR(x) (x)
#define HOST1X_HV_CMDFIFO_PEEK_CTRL_CHANNEL(x) ((x) << 16)
#define HOST1X_HV_CMDFIFO_PEEK_CTRL_ENABLE BIT(31)
#define HOST1X_HV_CMDFIFO_PEEK_READ 0x2340
#define HOST1X_HV_CMDFIFO_PEEK_PTRS 0x2344
#define HOST1X_HV_CMDFIFO_PEEK_PTRS_WR_PTR_V(x) (((x) >> 16) & 0xfff)
#define HOST1X_HV_CMDFIFO_PEEK_PTRS_RD_PTR_V(x) ((x) & 0xfff)
#define HOST1X_HV_CMDFIFO_SETUP(x) (0x2588 + (x * 4))
#define HOST1X_HV_CMDFIFO_SETUP_LIMIT_V(x) (((x) >> 16) & 0xfff)
#define HOST1X_HV_CMDFIFO_SETUP_BASE_V(x) ((x) & 0xfff)
#define HOST1X_HV_ICG_EN_OVERRIDE 0x2aa8
/*
* Copyright (c) 2018 NVIDIA Corporation.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
/*
* Function naming determines intended use:
*
* <x>_r(void) : Returns the offset for register <x>.
*
* <x>_w(void) : Returns the word offset for word (4 byte) element <x>.
*
* <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits.
*
* <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted
* and masked to place it at field <y> of register <x>. This value
* can be |'d with others to produce a full register value for
* register <x>.
*
* <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This
* value can be ~'d and then &'d to clear the value of field <y> for
* register <x>.
*
* <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted
* to place it at field <y> of register <x>. This value can be |'d
* with others to produce a full register value for <x>.
*
* <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register
* <x> value 'r' after being shifted to place its LSB at bit 0.
* This value is suitable for direct comparison with other unshifted
* values appropriate for use in field <y> of register <x>.
*
* <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for
* field <y> of register <x>. This value is suitable for direct
* comparison with unshifted values appropriate for use in field <y>
* of register <x>.
*/
#ifndef HOST1X_HW_HOST1X07_UCLASS_H
#define HOST1X_HW_HOST1X07_UCLASS_H
static inline u32 host1x_uclass_incr_syncpt_r(void)
{
return 0x0;
}
#define HOST1X_UCLASS_INCR_SYNCPT \
host1x_uclass_incr_syncpt_r()
static inline u32 host1x_uclass_incr_syncpt_cond_f(u32 v)
{
return (v & 0xff) << 10;
}
#define HOST1X_UCLASS_INCR_SYNCPT_COND_F(v) \
host1x_uclass_incr_syncpt_cond_f(v)
static inline u32 host1x_uclass_incr_syncpt_indx_f(u32 v)
{
return (v & 0xff) << 0;
}
#define HOST1X_UCLASS_INCR_SYNCPT_INDX_F(v) \
host1x_uclass_incr_syncpt_indx_f(v)
static inline u32 host1x_uclass_wait_syncpt_r(void)
{
return 0x8;
}
#define HOST1X_UCLASS_WAIT_SYNCPT \
host1x_uclass_wait_syncpt_r()
static inline u32 host1x_uclass_wait_syncpt_indx_f(u32 v)
{
return (v & 0xff) << 24;
}
#define HOST1X_UCLASS_WAIT_SYNCPT_INDX_F(v) \
host1x_uclass_wait_syncpt_indx_f(v)
static inline u32 host1x_uclass_wait_syncpt_thresh_f(u32 v)
{
return (v & 0xffffff) << 0;
}
#define HOST1X_UCLASS_WAIT_SYNCPT_THRESH_F(v) \
host1x_uclass_wait_syncpt_thresh_f(v)
static inline u32 host1x_uclass_wait_syncpt_base_r(void)
{
return 0x9;
}
#define HOST1X_UCLASS_WAIT_SYNCPT_BASE \
host1x_uclass_wait_syncpt_base_r()
static inline u32 host1x_uclass_wait_syncpt_base_indx_f(u32 v)
{
return (v & 0xff) << 24;
}
#define HOST1X_UCLASS_WAIT_SYNCPT_BASE_INDX_F(v) \
host1x_uclass_wait_syncpt_base_indx_f(v)
static inline u32 host1x_uclass_wait_syncpt_base_base_indx_f(u32 v)
{
return (v & 0xff) << 16;
}
#define HOST1X_UCLASS_WAIT_SYNCPT_BASE_BASE_INDX_F(v) \
host1x_uclass_wait_syncpt_base_base_indx_f(v)
static inline u32 host1x_uclass_wait_syncpt_base_offset_f(u32 v)
{
return (v & 0xffff) << 0;
}
#define HOST1X_UCLASS_WAIT_SYNCPT_BASE_OFFSET_F(v) \
host1x_uclass_wait_syncpt_base_offset_f(v)
static inline u32 host1x_uclass_load_syncpt_base_r(void)
{
return 0xb;
}
#define HOST1X_UCLASS_LOAD_SYNCPT_BASE \
host1x_uclass_load_syncpt_base_r()
static inline u32 host1x_uclass_load_syncpt_base_base_indx_f(u32 v)
{
return (v & 0xff) << 24;
}
#define HOST1X_UCLASS_LOAD_SYNCPT_BASE_BASE_INDX_F(v) \
host1x_uclass_load_syncpt_base_base_indx_f(v)
static inline u32 host1x_uclass_load_syncpt_base_value_f(u32 v)
{
return (v & 0xffffff) << 0;
}
#define HOST1X_UCLASS_LOAD_SYNCPT_BASE_VALUE_F(v) \
host1x_uclass_load_syncpt_base_value_f(v)
static inline u32 host1x_uclass_incr_syncpt_base_base_indx_f(u32 v)
{
return (v & 0xff) << 24;
}
#define HOST1X_UCLASS_INCR_SYNCPT_BASE_BASE_INDX_F(v) \
host1x_uclass_incr_syncpt_base_base_indx_f(v)
static inline u32 host1x_uclass_incr_syncpt_base_offset_f(u32 v)
{
return (v & 0xffffff) << 0;
}
#define HOST1X_UCLASS_INCR_SYNCPT_BASE_OFFSET_F(v) \
host1x_uclass_incr_syncpt_base_offset_f(v)
static inline u32 host1x_uclass_indoff_r(void)
{
return 0x2d;
}
#define HOST1X_UCLASS_INDOFF \
host1x_uclass_indoff_r()
static inline u32 host1x_uclass_indoff_indbe_f(u32 v)
{
return (v & 0xf) << 28;
}
#define HOST1X_UCLASS_INDOFF_INDBE_F(v) \
host1x_uclass_indoff_indbe_f(v)
static inline u32 host1x_uclass_indoff_autoinc_f(u32 v)
{
return (v & 0x1) << 27;
}
#define HOST1X_UCLASS_INDOFF_AUTOINC_F(v) \
host1x_uclass_indoff_autoinc_f(v)
static inline u32 host1x_uclass_indoff_indmodid_f(u32 v)
{
return (v & 0xff) << 18;
}
#define HOST1X_UCLASS_INDOFF_INDMODID_F(v) \
host1x_uclass_indoff_indmodid_f(v)
static inline u32 host1x_uclass_indoff_indroffset_f(u32 v)
{
return (v & 0xffff) << 2;
}
#define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \
host1x_uclass_indoff_indroffset_f(v)
static inline u32 host1x_uclass_indoff_rwn_read_v(void)
{
return 1;
}
#define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \
host1x_uclass_indoff_indroffset_f(v)
#endif
/*
* Copyright (c) 2018 NVIDIA Corporation.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#define HOST1X_CHANNEL_DMASTART 0x0000
#define HOST1X_CHANNEL_DMASTART_HI 0x0004
#define HOST1X_CHANNEL_DMAPUT 0x0008
#define HOST1X_CHANNEL_DMAPUT_HI 0x000c
#define HOST1X_CHANNEL_DMAGET 0x0010
#define HOST1X_CHANNEL_DMAGET_HI 0x0014
#define HOST1X_CHANNEL_DMAEND 0x0018
#define HOST1X_CHANNEL_DMAEND_HI 0x001c
#define HOST1X_CHANNEL_DMACTRL 0x0020
#define HOST1X_CHANNEL_DMACTRL_DMASTOP BIT(0)
#define HOST1X_CHANNEL_DMACTRL_DMAGETRST BIT(1)
#define HOST1X_CHANNEL_DMACTRL_DMAINITGET BIT(2)
#define HOST1X_CHANNEL_CMDFIFO_STAT 0x0024
#define HOST1X_CHANNEL_CMDFIFO_STAT_EMPTY BIT(13)
#define HOST1X_CHANNEL_CMDFIFO_RDATA 0x0028
#define HOST1X_CHANNEL_CMDP_OFFSET 0x0030
#define HOST1X_CHANNEL_CMDP_CLASS 0x0034
#define HOST1X_CHANNEL_CHANNELSTAT 0x0038
#define HOST1X_CHANNEL_CMDPROC_STOP 0x0048
#define HOST1X_CHANNEL_TEARDOWN 0x004c
#define HOST1X_SYNC_SYNCPT_CPU_INCR(x) (0x6400 + 4 * (x))
#define HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(x) (0x6464 + 4 * (x))
#define HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(x) (0x652c + 4 * (x))
#define HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(x) (0x6590 + 4 * (x))
#define HOST1X_SYNC_SYNCPT(x) (0x8080 + 4 * (x))
#define HOST1X_SYNC_SYNCPT_INT_THRESH(x) (0x8d00 + 4 * (x))
#define HOST1X_SYNC_SYNCPT_CH_APP(x) (0xa604 + 4 * (x))
#define HOST1X_SYNC_SYNCPT_CH_APP_CH(v) (((v) & 0x3f) << 8)
......@@ -37,10 +37,12 @@ static void syncpt_restore(struct host1x_syncpt *sp)
*/
static void syncpt_restore_wait_base(struct host1x_syncpt *sp)
{
#if HOST1X_HW < 7
struct host1x *host = sp->host;
host1x_sync_writel(host, sp->base_val,
HOST1X_SYNC_SYNCPT_BASE(sp->id));
#endif
}
/*
......@@ -48,10 +50,12 @@ static void syncpt_restore_wait_base(struct host1x_syncpt *sp)
*/
static void syncpt_read_wait_base(struct host1x_syncpt *sp)
{
#if HOST1X_HW < 7
struct host1x *host = sp->host;
sp->base_val =
host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_BASE(sp->id));
#endif
}
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment