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. -----BEGIN PGP SIGNATURE----- iQJHBAABCAAxFiEEiOrDCAFJzPfAjcif3SOs138+s6EFAlwKeT4THHRyZWRpbmdA bnZpZGlhLmNvbQAKCRDdI6zXfz6zodDYEAC66KbXHSbu1Q4Y4gWA36bDS16F1MS6 rPb0j0WkhsGejuIS5xbays1OSgtraQSMF7g1CE/kBBmiQj+LsEh/+g4QKdTIxCWn rjsM1ak3Z4uKnHgWt+mpR9wIg2WgnqzzJGVWHbX6mzL9Et5PWhqPtfgqqgUhiGJ9 p/EqbSq0MeHgYs9z3F31P9dtnWrWrrTnlbajpEPeU+fvzBNnDLP75azZDfzE06qt d3y3e1clSQFHbEPuqqGzZyfs/aM4Fu/lLnJwgUd0bq5fVPLj7RQ8UUFz+ZmRb9py Z25Mu/Lnm6pw/FUGD50NYWuaseevLT2hmPAw2b2A95ST77TLsLRubu8wREF321GN yiAECjUNQhrfRX7NQ23ZlRDY5ExOWu57NRCYRleI3atDv+8/Is8faA60+s1EItyv rTB05GPPixFD/GZ5p2IR0rvUFc4B1Axdbbj2SDY/Ns/tB/he52YJaR1h+SjFaJ2O OBrErL46S/CTBIt9YLMnT1HjX8XPdZHR0YYZzs7EJ3pMa1hyIjTlbr/wb0VwzaTp H8j9+mlBTjD/iLW1QfSui/su+59r0DpsTy4n0MPrVC8cvpwSNDVw2u6x3TqAMxKw r0nb7vl9xF08Fx1ZviCkJ6tBnIWoLUzXqondNQQygwv7tH4dRb2elOTPhKPh3dUV OZNbiDTYdmH+6Q== =WHND -----END PGP SIGNATURE----- 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: Dave 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
This commit is contained in:
commit
29a1da27c4
|
@ -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;
|
||||
|
||||
return clk_prepare_enable(vic->clk);
|
||||
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;
|
||||
|
||||
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)
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* 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)
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* 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
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue