diff options
| author | Ishan Mittal <imittal@nvidia.com> | 2017-06-08 06:31:42 -0400 |
|---|---|---|
| committer | Ishan Mittal <imittal@nvidia.com> | 2017-06-08 06:31:42 -0400 |
| commit | 5a24ffca4f583fc2d8b6d23cdd72297b3bb0c56d (patch) | |
| tree | fa0ee36f270e4011ce4fb52945e4f28fdf240f8c /drivers/gpu | |
| parent | fabd083430a792135fb30ed3b25d9446a6df28e9 (diff) | |
| parent | 5edcd552af63efd15d532a406fdef1b55f167bdd (diff) | |
Merge 't18x/dev-kernel' into nvidia
Bug 200295104
Change-Id: I2885095688e942ef860cdcc808af4288f9523ab9
Diffstat (limited to 'drivers/gpu')
26 files changed, 2727 insertions, 0 deletions
diff --git a/drivers/gpu/drm/tegra/Makefile.t18x b/drivers/gpu/drm/tegra/Makefile.t18x new file mode 100644 index 000000000..ee133616a --- /dev/null +++ b/drivers/gpu/drm/tegra/Makefile.t18x | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | ccflags-y += -Idrivers/gpu/drm/tegra | ||
| 2 | ccflags-y += -I../t18x/drivers/gpu/drm/tegra | ||
| 3 | |||
| 4 | tegra-drm-t186-y = \ | ||
| 5 | vic_t186.o \ | ||
| 6 | nvenc_t186.o \ | ||
| 7 | nvdec_t186.o \ | ||
| 8 | nvjpg_t186.o \ | ||
| 9 | tsec_t186.o | ||
| 10 | |||
| 11 | obj-$(CONFIG_TEGRA_HOST1X) += tegra-drm-t186.o | ||
diff --git a/drivers/gpu/drm/tegra/nvdec_t186.c b/drivers/gpu/drm/tegra/nvdec_t186.c new file mode 100644 index 000000000..78d2235c1 --- /dev/null +++ b/drivers/gpu/drm/tegra/nvdec_t186.c | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "drm.h" | ||
| 18 | #include "nvdec_t186.h" | ||
| 19 | |||
| 20 | #include <linux/iommu.h> | ||
| 21 | #include <soc/tegra/kfuse.h> | ||
| 22 | |||
| 23 | static int nvdec_load_streamid_regs(struct tegra_drm_client *client) | ||
| 24 | { | ||
| 25 | struct nvdec *nvdec = to_nvdec(client); | ||
| 26 | int streamid = -EINVAL; | ||
| 27 | |||
| 28 | streamid = iommu_get_hwid(nvdec->dev->archdata.iommu, nvdec->dev, 0); | ||
| 29 | |||
| 30 | if (streamid >= 0) { | ||
| 31 | nvdec_writel(nvdec, streamid, NVDEC_THI_STREAMID0); | ||
| 32 | nvdec_writel(nvdec, streamid, NVDEC_THI_STREAMID1); | ||
| 33 | } | ||
| 34 | |||
| 35 | return 0; | ||
| 36 | } | ||
| 37 | |||
| 38 | static int nvdec_finalize_poweron(struct tegra_drm_client *client) | ||
| 39 | { | ||
| 40 | return tegra_kfuse_enable_sensing(); | ||
| 41 | } | ||
| 42 | |||
| 43 | static int nvdec_prepare_poweroff(struct tegra_drm_client *client) | ||
| 44 | { | ||
| 45 | tegra_kfuse_disable_sensing(); | ||
| 46 | return 0; | ||
| 47 | } | ||
| 48 | |||
| 49 | static const struct tegra_drm_client_ops nvdec_t186_ops = { | ||
| 50 | .open_channel = nvdec_open_channel, | ||
| 51 | .close_channel = nvdec_close_channel, | ||
| 52 | .submit = tegra_drm_submit, | ||
| 53 | .load_regs = nvdec_load_streamid_regs, | ||
| 54 | .finalize_poweron = nvdec_finalize_poweron, | ||
| 55 | .prepare_poweroff = nvdec_prepare_poweroff, | ||
| 56 | }; | ||
| 57 | |||
| 58 | const struct nvdec_config nvdec_t186_config = { | ||
| 59 | .ucode_name = "tegra18x/nvhost_nvdec030_ns.fw", | ||
| 60 | .ucode_name_bl = "tegra18x/nvhost_nvdec_bl030_prod.fw", | ||
| 61 | .ucode_name_ls = "tegra18x/nvhost_nvdec030_prod.fw", | ||
| 62 | .drm_client_ops = &nvdec_t186_ops, | ||
| 63 | }; | ||
diff --git a/drivers/gpu/drm/tegra/nvdec_t186.h b/drivers/gpu/drm/tegra/nvdec_t186.h new file mode 100644 index 000000000..8d57e1d59 --- /dev/null +++ b/drivers/gpu/drm/tegra/nvdec_t186.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef TEGRA_NVDEC_T186_H | ||
| 18 | #define TEGRA_NVDEC_T186_H | ||
| 19 | |||
| 20 | #include "nvdec.h" | ||
| 21 | |||
| 22 | #define NVDEC_THI_STREAMID0 0x30 | ||
| 23 | #define NVDEC_THI_STREAMID1 0x34 | ||
| 24 | |||
| 25 | extern const struct nvdec_config nvdec_t186_config; | ||
| 26 | |||
| 27 | #endif | ||
diff --git a/drivers/gpu/drm/tegra/nvenc_t186.c b/drivers/gpu/drm/tegra/nvenc_t186.c new file mode 100644 index 000000000..68cc6a7e5 --- /dev/null +++ b/drivers/gpu/drm/tegra/nvenc_t186.c | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "drm.h" | ||
| 18 | #include "nvenc_t186.h" | ||
| 19 | |||
| 20 | #include <linux/iommu.h> | ||
| 21 | |||
| 22 | static int nvenc_load_streamid_regs(struct tegra_drm_client *client) | ||
| 23 | { | ||
| 24 | struct nvenc *nvenc = to_nvenc(client); | ||
| 25 | int streamid = -EINVAL; | ||
| 26 | |||
| 27 | streamid = iommu_get_hwid(nvenc->dev->archdata.iommu, nvenc->dev, 0); | ||
| 28 | |||
| 29 | if (streamid >= 0) { | ||
| 30 | nvenc_writel(nvenc, streamid, NVENC_THI_STREAMID0); | ||
| 31 | nvenc_writel(nvenc, streamid, NVENC_THI_STREAMID1); | ||
| 32 | } | ||
| 33 | |||
| 34 | return 0; | ||
| 35 | } | ||
| 36 | |||
| 37 | static const struct tegra_drm_client_ops nvenc_t186_ops = { | ||
| 38 | .open_channel = nvenc_open_channel, | ||
| 39 | .close_channel = nvenc_close_channel, | ||
| 40 | .submit = tegra_drm_submit, | ||
| 41 | .load_regs = nvenc_load_streamid_regs, | ||
| 42 | }; | ||
| 43 | |||
| 44 | const struct nvenc_config nvenc_t186_config = { | ||
| 45 | .ucode_name = "tegra18x/nvhost_nvenc061.fw", | ||
| 46 | .drm_client_ops = &nvenc_t186_ops, | ||
| 47 | }; | ||
diff --git a/drivers/gpu/drm/tegra/nvenc_t186.h b/drivers/gpu/drm/tegra/nvenc_t186.h new file mode 100644 index 000000000..1ae36ec16 --- /dev/null +++ b/drivers/gpu/drm/tegra/nvenc_t186.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef TEGRA_NVENC_T186_H | ||
| 18 | #define TEGRA_NVENC_T186_H | ||
| 19 | |||
| 20 | #include "nvenc.h" | ||
| 21 | |||
| 22 | #define NVENC_THI_STREAMID0 0x30 | ||
| 23 | #define NVENC_THI_STREAMID1 0x34 | ||
| 24 | |||
| 25 | extern const struct nvenc_config nvenc_t186_config; | ||
| 26 | |||
| 27 | #endif | ||
diff --git a/drivers/gpu/drm/tegra/nvjpg_t186.c b/drivers/gpu/drm/tegra/nvjpg_t186.c new file mode 100644 index 000000000..af262c589 --- /dev/null +++ b/drivers/gpu/drm/tegra/nvjpg_t186.c | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "drm.h" | ||
| 18 | #include "nvjpg_t186.h" | ||
| 19 | |||
| 20 | #include <linux/iommu.h> | ||
| 21 | |||
| 22 | static int nvjpg_load_streamid_regs(struct tegra_drm_client *client) | ||
| 23 | { | ||
| 24 | struct nvjpg *nvjpg = to_nvjpg(client); | ||
| 25 | int streamid = -EINVAL; | ||
| 26 | |||
| 27 | streamid = iommu_get_hwid(nvjpg->dev->archdata.iommu, nvjpg->dev, 0); | ||
| 28 | |||
| 29 | if (streamid >= 0) { | ||
| 30 | nvjpg_writel(nvjpg, streamid, NVJPG_THI_STREAMID0); | ||
| 31 | nvjpg_writel(nvjpg, streamid, NVJPG_THI_STREAMID1); | ||
| 32 | } | ||
| 33 | |||
| 34 | return 0; | ||
| 35 | } | ||
| 36 | |||
| 37 | static const struct tegra_drm_client_ops nvjpg_t186_ops = { | ||
| 38 | .open_channel = nvjpg_open_channel, | ||
| 39 | .close_channel = nvjpg_close_channel, | ||
| 40 | .submit = tegra_drm_submit, | ||
| 41 | .load_regs = nvjpg_load_streamid_regs, | ||
| 42 | }; | ||
| 43 | |||
| 44 | const struct nvjpg_config nvjpg_t186_config = { | ||
| 45 | .ucode_name = "tegra18x/nvhost_nvjpg011.fw", | ||
| 46 | .drm_client_ops = &nvjpg_t186_ops, | ||
| 47 | }; | ||
diff --git a/drivers/gpu/drm/tegra/nvjpg_t186.h b/drivers/gpu/drm/tegra/nvjpg_t186.h new file mode 100644 index 000000000..a310e34c1 --- /dev/null +++ b/drivers/gpu/drm/tegra/nvjpg_t186.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef TEGRA_NVJPG_T186_H | ||
| 18 | #define TEGRA_NVJPG_T186_H | ||
| 19 | |||
| 20 | #include "nvjpg.h" | ||
| 21 | |||
| 22 | #define NVJPG_THI_STREAMID0 0x30 | ||
| 23 | #define NVJPG_THI_STREAMID1 0x34 | ||
| 24 | |||
| 25 | extern const struct nvjpg_config nvjpg_t186_config; | ||
| 26 | |||
| 27 | #endif | ||
diff --git a/drivers/gpu/drm/tegra/tsec_t186.c b/drivers/gpu/drm/tegra/tsec_t186.c new file mode 100644 index 000000000..5a47bbc28 --- /dev/null +++ b/drivers/gpu/drm/tegra/tsec_t186.c | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "drm.h" | ||
| 18 | #include "tsec_t186.h" | ||
| 19 | |||
| 20 | #include <linux/iommu.h> | ||
| 21 | |||
| 22 | static int tsec_load_streamid_regs(struct tegra_drm_client *client) | ||
| 23 | { | ||
| 24 | struct tsec *tsec = to_tsec(client); | ||
| 25 | int streamid = -EINVAL; | ||
| 26 | |||
| 27 | streamid = iommu_get_hwid(tsec->dev->archdata.iommu, tsec->dev, 0); | ||
| 28 | |||
| 29 | if (streamid >= 0) { | ||
| 30 | tsec_writel(tsec, streamid, TSEC_THI_STREAMID0); | ||
| 31 | tsec_writel(tsec, streamid, TSEC_THI_STREAMID1); | ||
| 32 | } | ||
| 33 | |||
| 34 | return 0; | ||
| 35 | } | ||
| 36 | |||
| 37 | static const struct tegra_drm_client_ops tsec_t186_ops = { | ||
| 38 | .open_channel = tsec_open_channel, | ||
| 39 | .close_channel = tsec_close_channel, | ||
| 40 | .submit = tegra_drm_submit, | ||
| 41 | .load_regs = tsec_load_streamid_regs, | ||
| 42 | }; | ||
| 43 | |||
| 44 | const struct tsec_config tsec_t186_config = { | ||
| 45 | .ucode_name = "tegra18x/nvhost_tsec.fw", | ||
| 46 | .drm_client_ops = &tsec_t186_ops, | ||
| 47 | .class_id = HOST1X_CLASS_TSEC, | ||
| 48 | }; | ||
| 49 | |||
| 50 | const struct tsec_config tsecb_t186_config = { | ||
| 51 | .ucode_name = "tegra18x/nvhost_tsec.fw", | ||
| 52 | .drm_client_ops = &tsec_t186_ops, | ||
| 53 | .class_id = HOST1X_CLASS_TSECB, | ||
| 54 | }; | ||
diff --git a/drivers/gpu/drm/tegra/tsec_t186.h b/drivers/gpu/drm/tegra/tsec_t186.h new file mode 100644 index 000000000..e78ea2cf8 --- /dev/null +++ b/drivers/gpu/drm/tegra/tsec_t186.h | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef TEGRA_TSEC_T186_H | ||
| 18 | #define TEGRA_TSEC_T186_H | ||
| 19 | |||
| 20 | #include "tsec.h" | ||
| 21 | |||
| 22 | #define TSEC_THI_STREAMID0 0x30 | ||
| 23 | #define TSEC_THI_STREAMID1 0x34 | ||
| 24 | |||
| 25 | extern const struct tsec_config tsec_t186_config; | ||
| 26 | extern const struct tsec_config tsecb_t186_config; | ||
| 27 | |||
| 28 | #endif | ||
diff --git a/drivers/gpu/drm/tegra/vic_t186.c b/drivers/gpu/drm/tegra/vic_t186.c new file mode 100644 index 000000000..c6efe1e86 --- /dev/null +++ b/drivers/gpu/drm/tegra/vic_t186.c | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "drm.h" | ||
| 18 | #include "vic_t186.h" | ||
| 19 | |||
| 20 | #include <linux/iommu.h> | ||
| 21 | |||
| 22 | static int vic_load_streamid_regs(struct tegra_drm_client *client) | ||
| 23 | { | ||
| 24 | struct vic *vic = to_vic(client); | ||
| 25 | int streamid = -EINVAL; | ||
| 26 | |||
| 27 | streamid = iommu_get_hwid(vic->dev->archdata.iommu, vic->dev, 0); | ||
| 28 | |||
| 29 | if (streamid >= 0) { | ||
| 30 | vic_writel(vic, streamid, VIC_THI_STREAMID0); | ||
| 31 | vic_writel(vic, streamid, VIC_THI_STREAMID1); | ||
| 32 | } | ||
| 33 | |||
| 34 | return 0; | ||
| 35 | } | ||
| 36 | |||
| 37 | static const struct tegra_drm_client_ops vic_t186_ops = { | ||
| 38 | .open_channel = vic_open_channel, | ||
| 39 | .close_channel = vic_close_channel, | ||
| 40 | .is_addr_reg = vic_is_addr_reg, | ||
| 41 | .submit = tegra_drm_submit, | ||
| 42 | .load_regs = vic_load_streamid_regs, | ||
| 43 | }; | ||
| 44 | |||
| 45 | const struct vic_config vic_t186_config = { | ||
| 46 | .ucode_name = "tegra18x/vic04_ucode.bin", | ||
| 47 | .drm_client_ops = &vic_t186_ops, | ||
| 48 | }; | ||
diff --git a/drivers/gpu/drm/tegra/vic_t186.h b/drivers/gpu/drm/tegra/vic_t186.h new file mode 100644 index 000000000..e819dd49d --- /dev/null +++ b/drivers/gpu/drm/tegra/vic_t186.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef TEGRA_VIC_T186_H | ||
| 18 | #define TEGRA_VIC_T186_H | ||
| 19 | |||
| 20 | #include "vic.h" | ||
| 21 | |||
| 22 | #define VIC_THI_STREAMID0 0x30 | ||
| 23 | #define VIC_THI_STREAMID1 0x34 | ||
| 24 | |||
| 25 | extern const struct vic_config vic_t186_config; | ||
| 26 | |||
| 27 | #endif | ||
diff --git a/drivers/gpu/host1x/Makefile.t18x b/drivers/gpu/host1x/Makefile.t18x new file mode 100644 index 000000000..25d54f73a --- /dev/null +++ b/drivers/gpu/host1x/Makefile.t18x | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | ccflags-y += -Idrivers/gpu/host1x | ||
| 2 | ccflags-y += -I../t18x/drivers/gpu/host1x | ||
| 3 | |||
| 4 | host1x-t186-y = \ | ||
| 5 | dev_t186.o \ | ||
| 6 | hw/host1x05.o | ||
| 7 | |||
| 8 | obj-$(CONFIG_TEGRA_HOST1X) += host1x-t186.o | ||
diff --git a/drivers/gpu/host1x/dev_t186.c b/drivers/gpu/host1x/dev_t186.c new file mode 100644 index 000000000..d29a48c68 --- /dev/null +++ b/drivers/gpu/host1x/dev_t186.c | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "dev.h" | ||
| 18 | #include "dev_t186.h" | ||
| 19 | |||
| 20 | #include "hw/host1x05.h" | ||
| 21 | |||
| 22 | struct host1x_info host1x05_info = { | ||
| 23 | .nb_channels = 63, | ||
| 24 | .nb_pts = 576, | ||
| 25 | .nb_mlocks = 24, | ||
| 26 | .nb_bases = 16, | ||
| 27 | .init = host1x05_init, | ||
| 28 | .sync_offset = 0x0, | ||
| 29 | .gather_filter_enabled = true, | ||
| 30 | }; | ||
| 31 | |||
| 32 | void host1x_writel(struct host1x *host1x, u32 v, u32 r) | ||
| 33 | { | ||
| 34 | writel(v, host1x->regs + r); | ||
| 35 | } | ||
| 36 | |||
| 37 | u32 host1x_readl(struct host1x *host1x, u32 r) | ||
| 38 | { | ||
| 39 | return readl(host1x->regs + r); | ||
| 40 | } | ||
diff --git a/drivers/gpu/host1x/dev_t186.h b/drivers/gpu/host1x/dev_t186.h new file mode 100644 index 000000000..be9726e88 --- /dev/null +++ b/drivers/gpu/host1x/dev_t186.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef HOST1X_DEV_T186_H | ||
| 18 | #define HOST1X_DEV_T186_H | ||
| 19 | |||
| 20 | #include "dev.h" | ||
| 21 | |||
| 22 | extern struct host1x_info host1x05_info; | ||
| 23 | |||
| 24 | void host1x_writel(struct host1x *host1x, u32 v, u32 r); | ||
| 25 | u32 host1x_readl(struct host1x *host1x, u32 r); | ||
| 26 | |||
| 27 | static inline void host1x_hw_sync_get_mutex_owner(struct host1x *host, | ||
| 28 | struct host1x_syncpt *sp, | ||
| 29 | unsigned int mutex_id, bool *cpu, bool *ch, | ||
| 30 | unsigned int *chid) | ||
| 31 | { | ||
| 32 | host->syncpt_op->get_mutex_owner(sp, mutex_id, cpu, ch, chid); | ||
| 33 | } | ||
| 34 | #endif | ||
diff --git a/drivers/gpu/host1x/hw/cdma_hw_t186.c b/drivers/gpu/host1x/hw/cdma_hw_t186.c new file mode 100644 index 000000000..e903f3e8b --- /dev/null +++ b/drivers/gpu/host1x/hw/cdma_hw_t186.c | |||
| @@ -0,0 +1,340 @@ | |||
| 1 | /* | ||
| 2 | * Tegra host1x Command DMA | ||
| 3 | * | ||
| 4 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms and conditions of the GNU General Public License, | ||
| 8 | * version 2, as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 13 | * more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/slab.h> | ||
| 20 | #include <linux/scatterlist.h> | ||
| 21 | #include <linux/dma-mapping.h> | ||
| 22 | |||
| 23 | #include "cdma.h" | ||
| 24 | #include "channel.h" | ||
| 25 | #include "dev.h" | ||
| 26 | #include "debug.h" | ||
| 27 | |||
| 28 | /* | ||
| 29 | * Put the restart at the end of pushbuffer memory | ||
| 30 | */ | ||
| 31 | static void push_buffer_init(struct push_buffer *pb) | ||
| 32 | { | ||
| 33 | *(u32 *)(pb->mapped + pb->size_bytes) = host1x_opcode_restart(0); | ||
| 34 | } | ||
| 35 | |||
| 36 | /* | ||
| 37 | * Increment timedout buffer's syncpt via CPU. | ||
| 38 | */ | ||
| 39 | static void cdma_timeout_handle(struct host1x_cdma *cdma, u32 getptr, | ||
| 40 | u32 nr_slots) | ||
| 41 | { | ||
| 42 | struct host1x *host1x = cdma_to_host1x(cdma); | ||
| 43 | struct push_buffer *pb = &cdma->push_buffer; | ||
| 44 | |||
| 45 | /* NOP all the PB slots */ | ||
| 46 | while (nr_slots--) { | ||
| 47 | u32 *p = (u32 *)(pb->mapped + getptr); | ||
| 48 | *(p++) = HOST1X_OPCODE_NOP; | ||
| 49 | *(p++) = HOST1X_OPCODE_NOP; | ||
| 50 | dev_dbg(host1x->dev, "%s: NOP at %pad+%#x\n", __func__, | ||
| 51 | &pb->phys, getptr); | ||
| 52 | getptr = (getptr + 8) & (pb->size_bytes - 1); | ||
| 53 | } | ||
| 54 | wmb(); | ||
| 55 | } | ||
| 56 | |||
| 57 | /* | ||
| 58 | * Start channel DMA | ||
| 59 | */ | ||
| 60 | static void cdma_start(struct host1x_cdma *cdma) | ||
| 61 | { | ||
| 62 | struct host1x_channel *ch = cdma_to_channel(cdma); | ||
| 63 | |||
| 64 | if (cdma->running) | ||
| 65 | return; | ||
| 66 | |||
| 67 | cdma->last_pos = cdma->push_buffer.pos; | ||
| 68 | |||
| 69 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP, | ||
| 70 | HOST1X_CHANNEL_DMACTRL); | ||
| 71 | |||
| 72 | /* set base, put and end pointer */ | ||
| 73 | host1x_ch_writel(ch, cdma->push_buffer.phys, HOST1X_CHANNEL_DMASTART); | ||
| 74 | host1x_ch_writel(ch, cdma->push_buffer.pos, HOST1X_CHANNEL_DMAPUT); | ||
| 75 | host1x_ch_writel(ch, cdma->push_buffer.phys + | ||
| 76 | cdma->push_buffer.size_bytes + 4, | ||
| 77 | HOST1X_CHANNEL_DMAEND); | ||
| 78 | |||
| 79 | /* reset GET */ | ||
| 80 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP | | ||
| 81 | HOST1X_CHANNEL_DMACTRL_DMAGETRST | | ||
| 82 | HOST1X_CHANNEL_DMACTRL_DMAINITGET, | ||
| 83 | HOST1X_CHANNEL_DMACTRL); | ||
| 84 | |||
| 85 | host1x_channel_enable_gather_filter(ch); | ||
| 86 | |||
| 87 | /* start the command DMA */ | ||
| 88 | host1x_ch_writel(ch, 0, HOST1X_CHANNEL_DMACTRL); | ||
| 89 | |||
| 90 | cdma->running = true; | ||
| 91 | } | ||
| 92 | |||
| 93 | /* | ||
| 94 | * Similar to cdma_start(), but rather than starting from an idle | ||
| 95 | * state (where DMA GET is set to DMA PUT), on a timeout we restore | ||
| 96 | * DMA GET from an explicit value (so DMA may again be pending). | ||
| 97 | */ | ||
| 98 | static void cdma_timeout_restart(struct host1x_cdma *cdma, u32 getptr) | ||
| 99 | { | ||
| 100 | struct host1x *host1x = cdma_to_host1x(cdma); | ||
| 101 | struct host1x_channel *ch = cdma_to_channel(cdma); | ||
| 102 | |||
| 103 | if (cdma->running) | ||
| 104 | return; | ||
| 105 | |||
| 106 | cdma->last_pos = cdma->push_buffer.pos; | ||
| 107 | |||
| 108 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP, | ||
| 109 | HOST1X_CHANNEL_DMACTRL); | ||
| 110 | |||
| 111 | /* set base, end pointer (all of memory) */ | ||
| 112 | host1x_ch_writel(ch, cdma->push_buffer.phys, HOST1X_CHANNEL_DMASTART); | ||
| 113 | host1x_ch_writel(ch, cdma->push_buffer.phys + | ||
| 114 | cdma->push_buffer.size_bytes, | ||
| 115 | HOST1X_CHANNEL_DMAEND); | ||
| 116 | |||
| 117 | /* set GET, by loading the value in PUT (then reset GET) */ | ||
| 118 | host1x_ch_writel(ch, getptr, HOST1X_CHANNEL_DMAPUT); | ||
| 119 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP | | ||
| 120 | HOST1X_CHANNEL_DMACTRL_DMAGETRST | | ||
| 121 | HOST1X_CHANNEL_DMACTRL_DMAINITGET, | ||
| 122 | HOST1X_CHANNEL_DMACTRL); | ||
| 123 | |||
| 124 | dev_dbg(host1x->dev, | ||
| 125 | "%s: DMA GET 0x%x, PUT HW 0x%x / shadow 0x%x\n", __func__, | ||
| 126 | host1x_ch_readl(ch, HOST1X_CHANNEL_DMAGET), | ||
| 127 | host1x_ch_readl(ch, HOST1X_CHANNEL_DMAPUT), | ||
| 128 | cdma->last_pos); | ||
| 129 | |||
| 130 | /* deassert GET reset and set PUT */ | ||
| 131 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP, | ||
| 132 | HOST1X_CHANNEL_DMACTRL); | ||
| 133 | host1x_ch_writel(ch, cdma->push_buffer.pos, HOST1X_CHANNEL_DMAPUT); | ||
| 134 | |||
| 135 | host1x_channel_enable_gather_filter(ch); | ||
| 136 | |||
| 137 | /* start the command DMA */ | ||
| 138 | host1x_ch_writel(ch, 0, HOST1X_CHANNEL_DMACTRL); | ||
| 139 | |||
| 140 | cdma->running = true; | ||
| 141 | } | ||
| 142 | |||
| 143 | /* | ||
| 144 | * Kick channel DMA into action by writing its PUT offset (if it has changed) | ||
| 145 | */ | ||
| 146 | static void cdma_flush(struct host1x_cdma *cdma) | ||
| 147 | { | ||
| 148 | struct host1x_channel *ch = cdma_to_channel(cdma); | ||
| 149 | |||
| 150 | if (cdma->push_buffer.pos != cdma->last_pos) { | ||
| 151 | host1x_ch_writel(ch, cdma->push_buffer.pos, | ||
| 152 | HOST1X_CHANNEL_DMAPUT); | ||
| 153 | cdma->last_pos = cdma->push_buffer.pos; | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | static void cdma_stop(struct host1x_cdma *cdma) | ||
| 158 | { | ||
| 159 | struct host1x_channel *ch = cdma_to_channel(cdma); | ||
| 160 | |||
| 161 | mutex_lock(&cdma->lock); | ||
| 162 | if (cdma->running) { | ||
| 163 | host1x_cdma_wait_locked(cdma, CDMA_EVENT_SYNC_QUEUE_EMPTY); | ||
| 164 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP, | ||
| 165 | HOST1X_CHANNEL_DMACTRL); | ||
| 166 | cdma->running = false; | ||
| 167 | } | ||
| 168 | mutex_unlock(&cdma->lock); | ||
| 169 | } | ||
| 170 | |||
| 171 | /* | ||
| 172 | * Stops both channel's command processor and CDMA immediately. | ||
| 173 | * Also, tears down the channel and resets corresponding module. | ||
| 174 | */ | ||
| 175 | static void cdma_freeze(struct host1x_cdma *cdma) | ||
| 176 | { | ||
| 177 | struct host1x *host = cdma_to_host1x(cdma); | ||
| 178 | struct host1x_channel *ch = cdma_to_channel(cdma); | ||
| 179 | u32 cmdproc_stop; | ||
| 180 | |||
| 181 | if (cdma->torndown && !cdma->running) { | ||
| 182 | dev_warn(host->dev, "Already torn down\n"); | ||
| 183 | return; | ||
| 184 | } | ||
| 185 | |||
| 186 | dev_dbg(host->dev, "freezing channel (id %d)\n", ch->id); | ||
| 187 | |||
| 188 | cmdproc_stop = host1x_ch_readl(ch, HOST1X_SYNC_CMDPROC_STOP); | ||
| 189 | cmdproc_stop |= BIT(0); | ||
| 190 | host1x_ch_writel(ch, cmdproc_stop, HOST1X_SYNC_CMDPROC_STOP); | ||
| 191 | |||
| 192 | dev_dbg(host->dev, "%s: DMA GET 0x%x, PUT HW 0x%x / shadow 0x%x\n", | ||
| 193 | __func__, host1x_ch_readl(ch, HOST1X_CHANNEL_DMAGET), | ||
| 194 | host1x_ch_readl(ch, HOST1X_CHANNEL_DMAPUT), | ||
| 195 | cdma->last_pos); | ||
| 196 | |||
| 197 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP, | ||
| 198 | HOST1X_CHANNEL_DMACTRL); | ||
| 199 | |||
| 200 | host1x_ch_writel(ch, BIT(0), HOST1X_SYNC_CH_TEARDOWN); | ||
| 201 | |||
| 202 | cdma->running = false; | ||
| 203 | cdma->torndown = true; | ||
| 204 | } | ||
| 205 | |||
| 206 | static void cdma_resume(struct host1x_cdma *cdma, u32 getptr) | ||
| 207 | { | ||
| 208 | struct host1x *host1x = cdma_to_host1x(cdma); | ||
| 209 | struct host1x_channel *ch = cdma_to_channel(cdma); | ||
| 210 | u32 cmdproc_stop; | ||
| 211 | |||
| 212 | dev_dbg(host1x->dev, | ||
| 213 | "resuming channel (id %d, DMAGET restart = 0x%x)\n", | ||
| 214 | ch->id, getptr); | ||
| 215 | |||
| 216 | cmdproc_stop = host1x_ch_readl(ch, HOST1X_SYNC_CMDPROC_STOP); | ||
| 217 | cmdproc_stop &= ~(BIT(0)); | ||
| 218 | host1x_ch_writel(ch, cmdproc_stop, HOST1X_SYNC_CMDPROC_STOP); | ||
| 219 | |||
| 220 | cdma->torndown = false; | ||
| 221 | cdma_timeout_restart(cdma, getptr); | ||
| 222 | } | ||
| 223 | |||
| 224 | /* | ||
| 225 | * If this timeout fires, it indicates the current sync_queue entry has | ||
| 226 | * exceeded its TTL and the userctx should be timed out and remaining | ||
| 227 | * submits already issued cleaned up (future submits return an error). | ||
| 228 | */ | ||
| 229 | static void cdma_timeout_handler(struct work_struct *work) | ||
| 230 | { | ||
| 231 | struct host1x_cdma *cdma; | ||
| 232 | struct host1x *host1x; | ||
| 233 | struct host1x_channel *ch; | ||
| 234 | bool has_timedout = 0; | ||
| 235 | |||
| 236 | u32 prev_cmdproc, cmdproc_stop; | ||
| 237 | |||
| 238 | unsigned int i; | ||
| 239 | |||
| 240 | cdma = container_of(to_delayed_work(work), struct host1x_cdma, | ||
| 241 | timeout.wq); | ||
| 242 | host1x = cdma_to_host1x(cdma); | ||
| 243 | ch = cdma_to_channel(cdma); | ||
| 244 | |||
| 245 | host1x_debug_dump(cdma_to_host1x(cdma)); | ||
| 246 | |||
| 247 | mutex_lock(&cdma->lock); | ||
| 248 | |||
| 249 | if (!cdma->timeout.client) { | ||
| 250 | dev_dbg(host1x->dev, | ||
| 251 | "cdma_timeout: expired, but has no clientid\n"); | ||
| 252 | mutex_unlock(&cdma->lock); | ||
| 253 | return; | ||
| 254 | } | ||
| 255 | |||
| 256 | /* stop processing to get a clean snapshot */ | ||
| 257 | prev_cmdproc = host1x_ch_readl(ch, HOST1X_SYNC_CMDPROC_STOP); | ||
| 258 | cmdproc_stop = prev_cmdproc | BIT(0); | ||
| 259 | host1x_ch_writel(ch, cmdproc_stop, HOST1X_SYNC_CMDPROC_STOP); | ||
| 260 | |||
| 261 | dev_dbg(host1x->dev, "cdma_timeout: cmdproc was 0x%x is 0x%x\n", | ||
| 262 | prev_cmdproc, cmdproc_stop); | ||
| 263 | |||
| 264 | for (i = 0; i < cdma->timeout.num_syncpts; ++i) { | ||
| 265 | u32 id = cdma->timeout.syncpts[i].id; | ||
| 266 | u32 end = cdma->timeout.syncpts[i].end; | ||
| 267 | struct host1x_syncpt *syncpt = host1x_syncpt_get(host1x, id); | ||
| 268 | |||
| 269 | host1x_syncpt_load(syncpt); | ||
| 270 | |||
| 271 | has_timedout = !host1x_syncpt_is_expired(syncpt, end); | ||
| 272 | if (has_timedout) | ||
| 273 | break; | ||
| 274 | } | ||
| 275 | |||
| 276 | /* has buffer actually completed? */ | ||
| 277 | if (!has_timedout) { | ||
| 278 | dev_dbg(host1x->dev, | ||
| 279 | "cdma_timeout: expired, but buffer had completed\n"); | ||
| 280 | /* restore */ | ||
| 281 | cmdproc_stop = prev_cmdproc & ~(BIT(0)); | ||
| 282 | host1x_ch_writel(ch, cmdproc_stop, | ||
| 283 | HOST1X_SYNC_CMDPROC_STOP); | ||
| 284 | mutex_unlock(&cdma->lock); | ||
| 285 | return; | ||
| 286 | } | ||
| 287 | |||
| 288 | for (i = 0; i < cdma->timeout.num_syncpts; ++i) { | ||
| 289 | u32 id = cdma->timeout.syncpts[i].id; | ||
| 290 | struct host1x_syncpt *syncpt = host1x_syncpt_get(host1x, id); | ||
| 291 | u32 syncpt_val = host1x_syncpt_read_min(syncpt); | ||
| 292 | |||
| 293 | dev_warn(host1x->dev, "%s: timeout: %d (%s), HW thresh %d, done %d\n", | ||
| 294 | __func__, syncpt->id, syncpt->name, | ||
| 295 | syncpt_val, syncpt_val); | ||
| 296 | } | ||
| 297 | |||
| 298 | /* stop HW, resetting channel/module */ | ||
| 299 | host1x_hw_cdma_freeze(host1x, cdma); | ||
| 300 | |||
| 301 | host1x_cdma_update_sync_queue(cdma, ch->dev); | ||
| 302 | mutex_unlock(&cdma->lock); | ||
| 303 | } | ||
| 304 | |||
| 305 | /* | ||
| 306 | * Init timeout resources | ||
| 307 | */ | ||
| 308 | static int cdma_timeout_init(struct host1x_cdma *cdma) | ||
| 309 | { | ||
| 310 | INIT_DELAYED_WORK(&cdma->timeout.wq, cdma_timeout_handler); | ||
| 311 | cdma->timeout.initialized = true; | ||
| 312 | |||
| 313 | return 0; | ||
| 314 | } | ||
| 315 | |||
| 316 | /* | ||
| 317 | * Clean up timeout resources | ||
| 318 | */ | ||
| 319 | static void cdma_timeout_destroy(struct host1x_cdma *cdma) | ||
| 320 | { | ||
| 321 | if (cdma->timeout.initialized) | ||
| 322 | cancel_delayed_work(&cdma->timeout.wq); | ||
| 323 | cdma->timeout.initialized = false; | ||
| 324 | } | ||
| 325 | |||
| 326 | static const struct host1x_cdma_ops host1x_cdma_t186_ops = { | ||
| 327 | .start = cdma_start, | ||
| 328 | .stop = cdma_stop, | ||
| 329 | .flush = cdma_flush, | ||
| 330 | |||
| 331 | .timeout_init = cdma_timeout_init, | ||
| 332 | .timeout_destroy = cdma_timeout_destroy, | ||
| 333 | .freeze = cdma_freeze, | ||
| 334 | .resume = cdma_resume, | ||
| 335 | .timeout_handle = cdma_timeout_handle, | ||
| 336 | }; | ||
| 337 | |||
| 338 | static const struct host1x_pushbuffer_ops host1x_pushbuffer_t186_ops = { | ||
| 339 | .init = push_buffer_init, | ||
| 340 | }; | ||
diff --git a/drivers/gpu/host1x/hw/channel_hw_t186.c b/drivers/gpu/host1x/hw/channel_hw_t186.c new file mode 100644 index 000000000..256368f29 --- /dev/null +++ b/drivers/gpu/host1x/hw/channel_hw_t186.c | |||
| @@ -0,0 +1,302 @@ | |||
| 1 | /* | ||
| 2 | * Tegra host1x Channel | ||
| 3 | * | ||
| 4 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms and conditions of the GNU General Public License, | ||
| 8 | * version 2, as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 13 | * more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/host1x.h> | ||
| 20 | #include <linux/slab.h> | ||
| 21 | #include <linux/iommu.h> | ||
| 22 | #include <linux/pm_runtime.h> | ||
| 23 | |||
| 24 | #include <trace/events/host1x.h> | ||
| 25 | |||
| 26 | #include "dev_t186.h" | ||
| 27 | #include "channel.h" | ||
| 28 | #include "intr.h" | ||
| 29 | #include "job.h" | ||
| 30 | |||
| 31 | #define TRACE_MAX_LENGTH 128U | ||
| 32 | |||
| 33 | static void trace_write_gather(struct host1x_cdma *cdma, struct host1x_bo *bo, | ||
| 34 | u32 offset, u32 words) | ||
| 35 | { | ||
| 36 | struct device *dev = cdma_to_channel(cdma)->dev; | ||
| 37 | void *mem = NULL; | ||
| 38 | |||
| 39 | if (host1x_debug_trace_cmdbuf) | ||
| 40 | mem = host1x_bo_mmap(bo); | ||
| 41 | |||
| 42 | if (mem) { | ||
| 43 | u32 i; | ||
| 44 | /* | ||
| 45 | * Write in batches of 128 as there seems to be a limit | ||
| 46 | * of how much you can output to ftrace at once. | ||
| 47 | */ | ||
| 48 | for (i = 0; i < words; i += TRACE_MAX_LENGTH) { | ||
| 49 | u32 num_words = min(words - i, TRACE_MAX_LENGTH); | ||
| 50 | u32 next_offset = offset + i * sizeof(u32); | ||
| 51 | |||
| 52 | trace_host1x_cdma_push_gather(dev_name(dev), bo, | ||
| 53 | num_words, | ||
| 54 | next_offset, | ||
| 55 | mem); | ||
| 56 | } | ||
| 57 | |||
| 58 | host1x_bo_munmap(bo, mem); | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | static void channel_push_wait(struct host1x_channel *channel, | ||
| 63 | u32 id, u32 thresh) | ||
| 64 | { | ||
| 65 | host1x_cdma_push(&channel->cdma, | ||
| 66 | host1x_opcode_setclass(HOST1X_CLASS_HOST1X, | ||
| 67 | HOST1X_UCLASS_LOAD_SYNCPT_PAYLOAD_32, 1), | ||
| 68 | thresh); | ||
| 69 | host1x_cdma_push(&channel->cdma, | ||
| 70 | host1x_opcode_setclass(HOST1X_CLASS_HOST1X, | ||
| 71 | HOST1X_UCLASS_WAIT_SYNCPT_32, 1), | ||
| 72 | id); | ||
| 73 | } | ||
| 74 | |||
| 75 | static inline void serialize(struct host1x_job *job) | ||
| 76 | { | ||
| 77 | struct host1x_channel *ch = job->channel; | ||
| 78 | struct host1x *host = dev_get_drvdata(ch->dev->parent); | ||
| 79 | unsigned int i; | ||
| 80 | |||
| 81 | for (i = 0; i < job->num_syncpts; ++i) { | ||
| 82 | u32 syncpt_id = job->syncpts[i].id; | ||
| 83 | struct host1x_syncpt *syncpt = | ||
| 84 | host1x_syncpt_get(host, syncpt_id); | ||
| 85 | |||
| 86 | /* | ||
| 87 | * Force serialization by inserting a host wait for the | ||
| 88 | * previous job to finish before this one can commence. | ||
| 89 | */ | ||
| 90 | channel_push_wait(ch, syncpt_id, host1x_syncpt_read_max(syncpt)); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | static void add_sync_waits(struct host1x_job *job) | ||
| 95 | { | ||
| 96 | struct host1x *host = dev_get_drvdata(job->channel->dev->parent); | ||
| 97 | unsigned int i; | ||
| 98 | |||
| 99 | for (i = 0; i < job->num_gathers; i++) { | ||
| 100 | struct host1x_job_gather *g = &job->gathers[i]; | ||
| 101 | |||
| 102 | if (g->pre_fence) | ||
| 103 | host1x_sync_fence_wait(g->pre_fence, host, | ||
| 104 | job->channel); | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | static void submit_gathers(struct host1x_job *job) | ||
| 109 | { | ||
| 110 | struct host1x_cdma *cdma = &job->channel->cdma; | ||
| 111 | unsigned int i; | ||
| 112 | u32 cur_class = 0; | ||
| 113 | |||
| 114 | cur_class = HOST1X_CLASS_HOST1X; | ||
| 115 | host1x_cdma_push(cdma, | ||
| 116 | host1x_opcode_acquire_mlock(cur_class), | ||
| 117 | host1x_opcode_setclass(cur_class, 0, 0)); | ||
| 118 | |||
| 119 | add_sync_waits(job); | ||
| 120 | |||
| 121 | for (i = 0; i < job->num_gathers; i++) { | ||
| 122 | struct host1x_job_gather *g = &job->gathers[i]; | ||
| 123 | u32 op1 = host1x_opcode_gather(g->words); | ||
| 124 | u32 op2 = g->base + g->offset; | ||
| 125 | |||
| 126 | /* add a setclass for modules that require it */ | ||
| 127 | if (cur_class != g->class_id) { | ||
| 128 | if (cur_class) | ||
| 129 | host1x_cdma_push(cdma, | ||
| 130 | HOST1X_OPCODE_NOP, | ||
| 131 | host1x_opcode_release_mlock(cur_class)); | ||
| 132 | |||
| 133 | host1x_cdma_push(cdma, | ||
| 134 | host1x_opcode_acquire_mlock(g->class_id), | ||
| 135 | host1x_opcode_setclass(g->class_id, 0, 0)); | ||
| 136 | cur_class = g->class_id; | ||
| 137 | } | ||
| 138 | |||
| 139 | trace_write_gather(cdma, g->bo, g->offset, op1 & 0xffff); | ||
| 140 | host1x_cdma_push(cdma, op1, op2); | ||
| 141 | } | ||
| 142 | |||
| 143 | if (job->serialize) | ||
| 144 | serialize(job); | ||
| 145 | |||
| 146 | if (cur_class) | ||
| 147 | host1x_cdma_push(cdma, | ||
| 148 | HOST1X_OPCODE_NOP, | ||
| 149 | host1x_opcode_release_mlock(cur_class)); | ||
| 150 | } | ||
| 151 | |||
| 152 | static inline void synchronize_syncpt_base(struct host1x_job *job) | ||
| 153 | { | ||
| 154 | struct host1x_channel *ch = job->channel; | ||
| 155 | struct host1x *host = dev_get_drvdata(ch->dev->parent); | ||
| 156 | unsigned int i; | ||
| 157 | |||
| 158 | for (i = 0; i < job->num_syncpts; ++i) { | ||
| 159 | u32 syncpt_id = job->syncpts[i].id; | ||
| 160 | struct host1x_syncpt *syncpt = | ||
| 161 | host1x_syncpt_get(host, syncpt_id); | ||
| 162 | u32 base_id, value; | ||
| 163 | |||
| 164 | if (!syncpt->base) | ||
| 165 | continue; | ||
| 166 | |||
| 167 | value = host1x_syncpt_read_max(syncpt); | ||
| 168 | base_id = syncpt->base->id; | ||
| 169 | |||
| 170 | host1x_cdma_push(&job->channel->cdma, | ||
| 171 | host1x_opcode_setclass(HOST1X_CLASS_HOST1X, | ||
| 172 | HOST1X_UCLASS_LOAD_SYNCPT_BASE, 1), | ||
| 173 | HOST1X_UCLASS_LOAD_SYNCPT_BASE_BASE_INDX_F(base_id) | | ||
| 174 | HOST1X_UCLASS_LOAD_SYNCPT_BASE_VALUE_F(value)); | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | static int channel_submit(struct host1x_job *job) | ||
| 179 | { | ||
| 180 | struct host1x_channel *ch = job->channel; | ||
| 181 | struct host1x_syncpt *syncpt; | ||
| 182 | u32 prev_max = 0; | ||
| 183 | int err; | ||
| 184 | struct host1x_waitlist *completed_waiter[job->num_syncpts]; | ||
| 185 | struct host1x *host = dev_get_drvdata(ch->dev->parent); | ||
| 186 | unsigned int i; | ||
| 187 | int streamid = 0; | ||
| 188 | |||
| 189 | trace_host1x_channel_submit(dev_name(ch->dev), | ||
| 190 | job->num_gathers, job->num_relocs, | ||
| 191 | job->num_waitchk, job->syncpts[0].id, | ||
| 192 | job->syncpts[0].incrs); | ||
| 193 | |||
| 194 | /* before error checks, return current max */ | ||
| 195 | syncpt = host1x_syncpt_get(host, job->syncpts[0].id); | ||
| 196 | prev_max = host1x_syncpt_read_max(syncpt); | ||
| 197 | |||
| 198 | /* keep device powered on */ | ||
| 199 | for (i = 0; i < job->num_syncpts; ++i) | ||
| 200 | pm_runtime_get_sync(ch->dev); | ||
| 201 | |||
| 202 | /* get submit lock */ | ||
| 203 | err = mutex_lock_interruptible(&ch->submitlock); | ||
| 204 | if (err) | ||
| 205 | goto error; | ||
| 206 | |||
| 207 | for (i = 0; i < job->num_syncpts; i++) { | ||
| 208 | completed_waiter[i] = kzalloc(sizeof(*completed_waiter[i]), | ||
| 209 | GFP_KERNEL); | ||
| 210 | if (!completed_waiter[i]) { | ||
| 211 | mutex_unlock(&ch->submitlock); | ||
| 212 | err = -ENOMEM; | ||
| 213 | goto error; | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | streamid = iommu_get_hwid(host->dev->archdata.iommu, host->dev, 0); | ||
| 218 | if (streamid >= 0) | ||
| 219 | host1x_ch_writel(ch, streamid, HOST1X_CHANNEL_SMMU_STREAMID); | ||
| 220 | |||
| 221 | /* begin a CDMA submit */ | ||
| 222 | err = host1x_cdma_begin(&ch->cdma, job); | ||
| 223 | if (err) { | ||
| 224 | mutex_unlock(&ch->submitlock); | ||
| 225 | goto error; | ||
| 226 | } | ||
| 227 | |||
| 228 | /* Synchronize base register to allow using it for relative waiting */ | ||
| 229 | synchronize_syncpt_base(job); | ||
| 230 | |||
| 231 | /* Increment syncpoint maximum values */ | ||
| 232 | for (i = 0; i < job->num_syncpts; ++i) { | ||
| 233 | u32 id; | ||
| 234 | u32 incrs; | ||
| 235 | |||
| 236 | id = job->syncpts[i].id; | ||
| 237 | incrs = job->syncpts[i].incrs; | ||
| 238 | syncpt = host1x_syncpt_get(host, id); | ||
| 239 | job->syncpts[i].end = host1x_syncpt_incr_max(syncpt, incrs); | ||
| 240 | } | ||
| 241 | |||
| 242 | submit_gathers(job); | ||
| 243 | |||
| 244 | /* end CDMA submit & stash pinned hMems into sync queue */ | ||
| 245 | host1x_cdma_end(&ch->cdma, job); | ||
| 246 | |||
| 247 | trace_host1x_channel_submitted(dev_name(ch->dev), prev_max, | ||
| 248 | job->syncpts[0].end); | ||
| 249 | |||
| 250 | /* schedule submit complete interrupts */ | ||
| 251 | for (i = 0; i < job->num_syncpts; ++i) { | ||
| 252 | u32 syncpt_id = job->syncpts[i].id; | ||
| 253 | u32 syncpt_end = job->syncpts[i].end; | ||
| 254 | |||
| 255 | err = host1x_intr_add_action(host, syncpt_id, syncpt_end, | ||
| 256 | HOST1X_INTR_ACTION_SUBMIT_COMPLETE, | ||
| 257 | ch, completed_waiter[i], NULL); | ||
| 258 | completed_waiter[i] = NULL; | ||
| 259 | WARN(err, "Failed to set submit complete interrupt"); | ||
| 260 | } | ||
| 261 | |||
| 262 | mutex_unlock(&ch->submitlock); | ||
| 263 | |||
| 264 | return 0; | ||
| 265 | |||
| 266 | error: | ||
| 267 | for (i = 0; i < job->num_syncpts; i++) | ||
| 268 | kfree(completed_waiter[i]); | ||
| 269 | return err; | ||
| 270 | } | ||
| 271 | |||
| 272 | static int host1x_channel_init(struct host1x_channel *ch, struct host1x *dev, | ||
| 273 | unsigned int index) | ||
| 274 | { | ||
| 275 | ch->id = index; | ||
| 276 | mutex_init(&ch->reflock); | ||
| 277 | mutex_init(&ch->submitlock); | ||
| 278 | |||
| 279 | ch->regs = dev->regs + (HOST1X_CHANNEL_CH_APERTURE_START + | ||
| 280 | index * HOST1X_CHANNEL_CH_APERTURE_SIZE); | ||
| 281 | return 0; | ||
| 282 | } | ||
| 283 | |||
| 284 | static void channel_enable_gather_filter(struct host1x_channel *ch) | ||
| 285 | { | ||
| 286 | struct host1x *host = dev_get_drvdata(ch->dev->parent); | ||
| 287 | u32 val; | ||
| 288 | |||
| 289 | val = host1x_readl(host, HOST1X_CHANNEL_FILTER_GBUFFER | ||
| 290 | + BIT_WORD(ch->id) * sizeof(u32)); | ||
| 291 | |||
| 292 | host1x_writel(host, val | BIT_MASK(ch->id), | ||
| 293 | HOST1X_CHANNEL_FILTER_GBUFFER | ||
| 294 | + BIT_WORD(ch->id) * sizeof(u32)); | ||
| 295 | } | ||
| 296 | |||
| 297 | static const struct host1x_channel_ops host1x_channel_t186_ops = { | ||
| 298 | .init = host1x_channel_init, | ||
| 299 | .submit = channel_submit, | ||
| 300 | .push_wait = channel_push_wait, | ||
| 301 | .enable_gather_filter = channel_enable_gather_filter, | ||
| 302 | }; | ||
diff --git a/drivers/gpu/host1x/hw/debug_hw_t186.c b/drivers/gpu/host1x/hw/debug_hw_t186.c new file mode 100644 index 000000000..d6111668e --- /dev/null +++ b/drivers/gpu/host1x/hw/debug_hw_t186.c | |||
| @@ -0,0 +1,288 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010 Google, Inc. | ||
| 3 | * Author: Erik Gilling <konkers@android.com> | ||
| 4 | * | ||
| 5 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. | ||
| 6 | * | ||
| 7 | * This software is licensed under the terms of the GNU General Public | ||
| 8 | * License version 2, as published by the Free Software Foundation, and | ||
| 9 | * may be copied, distributed, and modified under those terms. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include "dev.h" | ||
| 19 | #include "debug.h" | ||
| 20 | #include "cdma.h" | ||
| 21 | #include "channel.h" | ||
| 22 | |||
| 23 | #define HOST1X_DEBUG_MAX_PAGE_OFFSET 102400 | ||
| 24 | |||
| 25 | enum { | ||
| 26 | HOST1X_OPCODE_SETCLASS = 0x00, | ||
| 27 | HOST1X_OPCODE_INCR = 0x01, | ||
| 28 | HOST1X_OPCODE_NONINCR = 0x02, | ||
| 29 | HOST1X_OPCODE_MASK = 0x03, | ||
| 30 | HOST1X_OPCODE_IMM = 0x04, | ||
| 31 | HOST1X_OPCODE_RESTART = 0x05, | ||
| 32 | HOST1X_OPCODE_GATHER = 0x06, | ||
| 33 | HOST1X_OPCODE_EXTEND = 0x0e, | ||
| 34 | }; | ||
| 35 | |||
| 36 | enum { | ||
| 37 | HOST1X_OPCODE_EXTEND_ACQUIRE_MLOCK = 0x00, | ||
| 38 | HOST1X_OPCODE_EXTEND_RELEASE_MLOCK = 0x01, | ||
| 39 | }; | ||
| 40 | |||
| 41 | static unsigned int show_channel_command(struct output *o, u32 val) | ||
| 42 | { | ||
| 43 | unsigned mask; | ||
| 44 | unsigned subop; | ||
| 45 | |||
| 46 | switch (val >> 28) { | ||
| 47 | case HOST1X_OPCODE_SETCLASS: | ||
| 48 | mask = val & 0x3f; | ||
| 49 | if (mask) { | ||
| 50 | host1x_debug_output(o, "SETCL(class=%03x, offset=%03x, mask=%02x, [", | ||
| 51 | val >> 6 & 0x3ff, | ||
| 52 | val >> 16 & 0xfff, mask); | ||
| 53 | return hweight8(mask); | ||
| 54 | } else { | ||
| 55 | host1x_debug_output(o, "SETCL(class=%03x)\n", | ||
| 56 | val >> 6 & 0x3ff); | ||
| 57 | return 0; | ||
| 58 | } | ||
| 59 | |||
| 60 | case HOST1X_OPCODE_INCR: | ||
| 61 | host1x_debug_output(o, "INCR(offset=%03x, [", | ||
| 62 | val >> 16 & 0xfff); | ||
| 63 | return val & 0xffff; | ||
| 64 | |||
| 65 | case HOST1X_OPCODE_NONINCR: | ||
| 66 | host1x_debug_output(o, "NONINCR(offset=%03x, [", | ||
| 67 | val >> 16 & 0xfff); | ||
| 68 | return val & 0xffff; | ||
| 69 | |||
| 70 | case HOST1X_OPCODE_MASK: | ||
| 71 | mask = val & 0xffff; | ||
| 72 | host1x_debug_output(o, "MASK(offset=%03x, mask=%03x, [", | ||
| 73 | val >> 16 & 0xfff, mask); | ||
| 74 | return hweight16(mask); | ||
| 75 | |||
| 76 | case HOST1X_OPCODE_IMM: | ||
| 77 | host1x_debug_output(o, "IMM(offset=%03x, data=%03x)\n", | ||
| 78 | val >> 16 & 0xfff, val & 0xffff); | ||
| 79 | return 0; | ||
| 80 | |||
| 81 | case HOST1X_OPCODE_RESTART: | ||
| 82 | host1x_debug_output(o, "RESTART(offset=%08x)\n", val << 4); | ||
| 83 | return 0; | ||
| 84 | |||
| 85 | case HOST1X_OPCODE_GATHER: | ||
| 86 | host1x_debug_output(o, "GATHER(offset=%03x, insert=%d, type=%d, count=%04x, addr=[", | ||
| 87 | val >> 16 & 0xfff, val >> 15 & 0x1, | ||
| 88 | val >> 14 & 0x1, val & 0x3fff); | ||
| 89 | return 1; | ||
| 90 | |||
| 91 | case HOST1X_OPCODE_EXTEND: | ||
| 92 | subop = val >> 24 & 0xf; | ||
| 93 | if (subop == HOST1X_OPCODE_EXTEND_ACQUIRE_MLOCK) | ||
| 94 | host1x_debug_output(o, "ACQUIRE_MLOCK(index=%d)\n", | ||
| 95 | val & 0xff); | ||
| 96 | else if (subop == HOST1X_OPCODE_EXTEND_RELEASE_MLOCK) | ||
| 97 | host1x_debug_output(o, "RELEASE_MLOCK(index=%d)\n", | ||
| 98 | val & 0xff); | ||
| 99 | else | ||
| 100 | host1x_debug_output(o, "EXTEND_UNKNOWN(%08x)\n", val); | ||
| 101 | return 0; | ||
| 102 | |||
| 103 | default: | ||
| 104 | return 0; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | static void show_gather(struct output *o, phys_addr_t phys_addr, | ||
| 109 | unsigned int words, struct host1x_cdma *cdma, | ||
| 110 | phys_addr_t pin_addr, u32 *map_addr) | ||
| 111 | { | ||
| 112 | /* Map dmaget cursor to corresponding mem handle */ | ||
| 113 | u32 offset = phys_addr - pin_addr; | ||
| 114 | unsigned int data_count = 0, i; | ||
| 115 | |||
| 116 | /* | ||
| 117 | * Sometimes we're given different hardware address to the same | ||
| 118 | * page - in these cases the offset will get an invalid number and | ||
| 119 | * we just have to bail out. | ||
| 120 | */ | ||
| 121 | if (offset > HOST1X_DEBUG_MAX_PAGE_OFFSET) { | ||
| 122 | host1x_debug_output(o, "[address mismatch]\n"); | ||
| 123 | return; | ||
| 124 | } | ||
| 125 | |||
| 126 | for (i = 0; i < words; i++) { | ||
| 127 | u32 addr = phys_addr + i * 4; | ||
| 128 | u32 val = *(map_addr + offset / 4 + i); | ||
| 129 | |||
| 130 | if (!data_count) { | ||
| 131 | host1x_debug_output(o, "%08x: %08x:", addr, val); | ||
| 132 | data_count = show_channel_command(o, val); | ||
| 133 | } else { | ||
| 134 | host1x_debug_output(o, "%08x%s", val, | ||
| 135 | data_count > 0 ? ", " : "])\n"); | ||
| 136 | data_count--; | ||
| 137 | } | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma) | ||
| 142 | { | ||
| 143 | struct host1x_job *job; | ||
| 144 | |||
| 145 | list_for_each_entry(job, &cdma->sync_queue, list) { | ||
| 146 | int i; | ||
| 147 | host1x_debug_output(o, "\n%p: JOB, syncpt_id=%d, syncpt_val=%d, first_get=%08x, timeout=%d num_slots=%d, num_handles=%d\n", | ||
| 148 | job, | ||
| 149 | (job->syncpts ? job->syncpts[0].id : 0), | ||
| 150 | (job->syncpts ? job->syncpts[0].end : 0), | ||
| 151 | job->first_get, job->timeout, | ||
| 152 | job->num_slots, job->num_unpins); | ||
| 153 | |||
| 154 | for (i = 0; i < job->num_gathers; i++) { | ||
| 155 | struct host1x_job_gather *g = &job->gathers[i]; | ||
| 156 | u32 *mapped; | ||
| 157 | |||
| 158 | if (job->gather_copy_mapped) | ||
| 159 | mapped = (u32 *)job->gather_copy_mapped; | ||
| 160 | else | ||
| 161 | mapped = host1x_bo_mmap(g->bo); | ||
| 162 | |||
| 163 | if (!mapped) { | ||
| 164 | host1x_debug_output(o, "[could not mmap]\n"); | ||
| 165 | continue; | ||
| 166 | } | ||
| 167 | |||
| 168 | host1x_debug_output(o, " GATHER at %pad+%#x, %d words\n", | ||
| 169 | &g->base, g->offset, g->words); | ||
| 170 | |||
| 171 | show_gather(o, g->base + g->offset, g->words, cdma, | ||
| 172 | g->base, mapped); | ||
| 173 | |||
| 174 | if (!job->gather_copy_mapped) | ||
| 175 | host1x_bo_munmap(g->bo, mapped); | ||
| 176 | } | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | static void host1x_debug_show_channel_cdma(struct host1x *host, | ||
| 181 | struct host1x_channel *ch, | ||
| 182 | struct output *o) | ||
| 183 | { | ||
| 184 | struct host1x_cdma *cdma = &ch->cdma; | ||
| 185 | u32 val; | ||
| 186 | |||
| 187 | host1x_debug_output(o, "Host1x basic channel registers: \n"); | ||
| 188 | |||
| 189 | val = host1x_ch_readl(ch, HOST1X_CHANNEL_FIFOSTAT); | ||
| 190 | host1x_debug_output(o, "CMDFIFO_STAT_0: %08x\n", val); | ||
| 191 | val = host1x_ch_readl(ch, HOST1X_CHANNEL_RDATA); | ||
| 192 | host1x_debug_output(o, "CMDFIFO_RDATA_0: %08x\n", val); | ||
| 193 | val = host1x_ch_readl(ch, HOST1X_CHANNEL_CMDP_OFFSET); | ||
| 194 | host1x_debug_output(o, "CMDP_OFFSET_0: %08x\n", val); | ||
| 195 | val = host1x_ch_readl(ch, HOST1X_CHANNEL_CMDP_CLASS); | ||
| 196 | host1x_debug_output(o, "CMDP_CLASS_0: %08x\n", val); | ||
| 197 | val = host1x_ch_readl(ch, HOST1X_CHANNEL_CMDP_CHANNELSTAT); | ||
| 198 | host1x_debug_output(o, "CHANNELSTAT_0: %08x\n", val); | ||
| 199 | |||
| 200 | show_channel_gathers(o, cdma); | ||
| 201 | host1x_debug_output(o, "\n"); | ||
| 202 | } | ||
| 203 | |||
| 204 | static void host1x_debug_show_channel_fifo(struct host1x *host, | ||
| 205 | struct host1x_channel *ch, | ||
| 206 | struct output *o) | ||
| 207 | { | ||
| 208 | u32 val, rd_ptr, wr_ptr, start, end, temp; | ||
| 209 | unsigned int data_count = 0; | ||
| 210 | |||
| 211 | host1x_debug_output(o, "%d: fifo:\n", ch->id); | ||
| 212 | |||
| 213 | temp = host1x_sync_readl(host, HOST1X_THOST_COMMON_ICG_EN_OVERRIDE_0); | ||
| 214 | host1x_sync_writel(host, 0x1, HOST1X_THOST_COMMON_ICG_EN_OVERRIDE_0); | ||
| 215 | |||
| 216 | val = host1x_ch_readl(ch, HOST1X_CHANNEL_FIFOSTAT); | ||
| 217 | host1x_debug_output(o, "FIFOSTAT %08x\n", val); | ||
| 218 | if (HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_V(val)) { | ||
| 219 | host1x_debug_output(o, "[empty]\n"); | ||
| 220 | return; | ||
| 221 | } | ||
| 222 | |||
| 223 | host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL); | ||
| 224 | host1x_sync_writel(host, HOST1X_SYNC_CFPEEK_CTRL_ENA_F(1) | | ||
| 225 | HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(ch->id), | ||
| 226 | HOST1X_SYNC_CFPEEK_CTRL); | ||
| 227 | |||
| 228 | val = host1x_sync_readl(host, HOST1X_SYNC_CFPEEK_PTRS); | ||
| 229 | rd_ptr = HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_V(val); | ||
| 230 | wr_ptr = HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_V(val); | ||
| 231 | |||
| 232 | val = host1x_sync_readl(host, HOST1X_SYNC_CF_SETUP(ch->id)); | ||
| 233 | start = HOST1X_SYNC_CF_SETUP_BASE_V(val); | ||
| 234 | end = HOST1X_SYNC_CF_SETUP_LIMIT_V(val); | ||
| 235 | |||
| 236 | do { | ||
| 237 | host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL); | ||
| 238 | host1x_sync_writel(host, HOST1X_SYNC_CFPEEK_CTRL_ENA_F(1) | | ||
| 239 | HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(ch->id) | | ||
| 240 | HOST1X_SYNC_CFPEEK_CTRL_ADDR_F(rd_ptr), | ||
| 241 | HOST1X_SYNC_CFPEEK_CTRL); | ||
| 242 | val = host1x_sync_readl(host, HOST1X_SYNC_CFPEEK_READ); | ||
| 243 | |||
| 244 | if (!data_count) { | ||
| 245 | host1x_debug_output(o, "%08x:", val); | ||
| 246 | data_count = show_channel_command(o, val); | ||
| 247 | } else { | ||
| 248 | host1x_debug_output(o, "%08x%s", val, | ||
| 249 | data_count > 0 ? ", " : "])\n"); | ||
| 250 | data_count--; | ||
| 251 | } | ||
| 252 | |||
| 253 | if (rd_ptr == end) | ||
| 254 | rd_ptr = start; | ||
| 255 | else | ||
| 256 | rd_ptr++; | ||
| 257 | } while (rd_ptr != wr_ptr); | ||
| 258 | |||
| 259 | if (data_count) | ||
| 260 | host1x_debug_output(o, ", ...])\n"); | ||
| 261 | host1x_debug_output(o, "\n"); | ||
| 262 | |||
| 263 | host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL); | ||
| 264 | |||
| 265 | host1x_sync_writel(host, temp, HOST1X_THOST_COMMON_ICG_EN_OVERRIDE_0); | ||
| 266 | } | ||
| 267 | |||
| 268 | static void host1x_debug_show_mlocks(struct host1x *host, struct output *o) | ||
| 269 | { | ||
| 270 | int i; | ||
| 271 | unsigned int chid; | ||
| 272 | bool cpu, ch; | ||
| 273 | |||
| 274 | host1x_debug_output(o, "---- mlocks ----\n"); | ||
| 275 | for (i = 0; i < host1x_syncpt_nb_mlocks(host); i++) { | ||
| 276 | host1x_hw_sync_get_mutex_owner(host, host->syncpt, | ||
| 277 | i, &cpu, &ch, &chid); | ||
| 278 | if (ch) | ||
| 279 | host1x_debug_output(o, "%d: locked by channel %d\n", i, chid); | ||
| 280 | } | ||
| 281 | host1x_debug_output(o, "\n"); | ||
| 282 | } | ||
| 283 | |||
| 284 | static const struct host1x_debug_ops host1x_debug_t186_ops = { | ||
| 285 | .show_channel_cdma = host1x_debug_show_channel_cdma, | ||
| 286 | .show_channel_fifo = host1x_debug_show_channel_fifo, | ||
| 287 | .show_mlocks = host1x_debug_show_mlocks, | ||
| 288 | }; | ||
diff --git a/drivers/gpu/host1x/hw/host1x05.c b/drivers/gpu/host1x/hw/host1x05.c new file mode 100644 index 000000000..3a790bee4 --- /dev/null +++ b/drivers/gpu/host1x/hw/host1x05.c | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | /* include hw specification */ | ||
| 18 | #include "host1x05.h" | ||
| 19 | #include "host1x05_hardware.h" | ||
| 20 | |||
| 21 | /* include code */ | ||
| 22 | #include "cdma_hw_t186.c" | ||
| 23 | #include "channel_hw_t186.c" | ||
| 24 | #include "debug_hw_t186.c" | ||
| 25 | #include "intr_hw_t186.c" | ||
| 26 | #include "syncpt_hw_t186.c" | ||
| 27 | #include "stremid_hw_t186.c" | ||
| 28 | |||
| 29 | #include "dev.h" | ||
| 30 | |||
| 31 | int host1x05_init(struct host1x *host) | ||
| 32 | { | ||
| 33 | host->dev_op = &host1x_dev_t186_ops; | ||
| 34 | host->channel_op = &host1x_channel_t186_ops; | ||
| 35 | host->cdma_op = &host1x_cdma_t186_ops; | ||
| 36 | host->cdma_pb_op = &host1x_pushbuffer_t186_ops; | ||
| 37 | host->syncpt_op = &host1x_syncpt_t186_ops; | ||
| 38 | host->intr_op = &host1x_intr_t186_ops; | ||
| 39 | host->debug_op = &host1x_debug_t186_ops; | ||
| 40 | |||
| 41 | return 0; | ||
| 42 | } | ||
diff --git a/drivers/gpu/host1x/hw/host1x05.h b/drivers/gpu/host1x/hw/host1x05.h new file mode 100644 index 000000000..e1b842146 --- /dev/null +++ b/drivers/gpu/host1x/hw/host1x05.h | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef HOST1X_HOST1X05_H | ||
| 18 | #define HOST1X_HOST1X05_H | ||
| 19 | |||
| 20 | struct host1x; | ||
| 21 | |||
| 22 | int host1x05_init(struct host1x *host); | ||
| 23 | |||
| 24 | #endif | ||
diff --git a/drivers/gpu/host1x/hw/host1x05_hardware.h b/drivers/gpu/host1x/hw/host1x05_hardware.h new file mode 100644 index 000000000..add00014e --- /dev/null +++ b/drivers/gpu/host1x/hw/host1x05_hardware.h | |||
| @@ -0,0 +1,128 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef __HOST1X_HOST1X05_HARDWARE_H | ||
| 18 | #define __HOST1X_HOST1X05_HARDWARE_H | ||
| 19 | |||
| 20 | #include <linux/types.h> | ||
| 21 | #include <linux/bitops.h> | ||
| 22 | |||
| 23 | #include "hw_host1x05_channel.h" | ||
| 24 | #include "hw_host1x05_sync.h" | ||
| 25 | #include "hw_host1x05_uclass.h" | ||
| 26 | |||
| 27 | static inline u32 host1x_class_host_wait_syncpt( | ||
| 28 | unsigned indx, unsigned threshold) | ||
| 29 | { | ||
| 30 | return host1x_uclass_wait_syncpt_indx_f(indx) | ||
| 31 | | host1x_uclass_wait_syncpt_thresh_f(threshold); | ||
| 32 | } | ||
| 33 | |||
| 34 | static inline u32 host1x_class_host_load_syncpt_base( | ||
| 35 | unsigned indx, unsigned threshold) | ||
| 36 | { | ||
| 37 | return host1x_uclass_load_syncpt_base_base_indx_f(indx) | ||
| 38 | | host1x_uclass_load_syncpt_base_value_f(threshold); | ||
| 39 | } | ||
| 40 | |||
| 41 | static inline u32 host1x_class_host_wait_syncpt_base( | ||
| 42 | unsigned indx, unsigned base_indx, unsigned offset) | ||
| 43 | { | ||
| 44 | return host1x_uclass_wait_syncpt_base_indx_f(indx) | ||
| 45 | | host1x_uclass_wait_syncpt_base_base_indx_f(base_indx) | ||
| 46 | | host1x_uclass_wait_syncpt_base_offset_f(offset); | ||
| 47 | } | ||
| 48 | |||
| 49 | static inline u32 host1x_class_host_incr_syncpt_base( | ||
| 50 | unsigned base_indx, unsigned offset) | ||
| 51 | { | ||
| 52 | return host1x_uclass_incr_syncpt_base_base_indx_f(base_indx) | ||
| 53 | | host1x_uclass_incr_syncpt_base_offset_f(offset); | ||
| 54 | } | ||
| 55 | |||
| 56 | static inline u32 host1x_class_host_incr_syncpt( | ||
| 57 | unsigned cond, unsigned indx) | ||
| 58 | { | ||
| 59 | return host1x_uclass_incr_syncpt_cond_f(cond) | ||
| 60 | | host1x_uclass_incr_syncpt_indx_f(indx); | ||
| 61 | } | ||
| 62 | |||
| 63 | /* cdma opcodes */ | ||
| 64 | static inline u32 host1x_opcode_setclass( | ||
| 65 | unsigned class_id, unsigned offset, unsigned mask) | ||
| 66 | { | ||
| 67 | return (0 << 28) | (offset << 16) | (class_id << 6) | mask; | ||
| 68 | } | ||
| 69 | |||
| 70 | static inline u32 host1x_opcode_incr(unsigned offset, unsigned count) | ||
| 71 | { | ||
| 72 | return (1 << 28) | (offset << 16) | count; | ||
| 73 | } | ||
| 74 | |||
| 75 | static inline u32 host1x_opcode_nonincr(unsigned offset, unsigned count) | ||
| 76 | { | ||
| 77 | return (2 << 28) | (offset << 16) | count; | ||
| 78 | } | ||
| 79 | |||
| 80 | static inline u32 host1x_opcode_mask(unsigned offset, unsigned mask) | ||
| 81 | { | ||
| 82 | return (3 << 28) | (offset << 16) | mask; | ||
| 83 | } | ||
| 84 | |||
| 85 | static inline u32 host1x_opcode_imm(unsigned offset, unsigned value) | ||
| 86 | { | ||
| 87 | return (4 << 28) | (offset << 16) | value; | ||
| 88 | } | ||
| 89 | |||
| 90 | static inline u32 host1x_opcode_imm_incr_syncpt(unsigned cond, unsigned indx) | ||
| 91 | { | ||
| 92 | return host1x_opcode_imm(host1x_uclass_incr_syncpt_r(), | ||
| 93 | host1x_class_host_incr_syncpt(cond, indx)); | ||
| 94 | } | ||
| 95 | |||
| 96 | static inline u32 host1x_opcode_restart(unsigned address) | ||
| 97 | { | ||
| 98 | return (5 << 28) | (address >> 4); | ||
| 99 | } | ||
| 100 | |||
| 101 | static inline u32 host1x_opcode_gather(unsigned count) | ||
| 102 | { | ||
| 103 | return (6 << 28) | count; | ||
| 104 | } | ||
| 105 | |||
| 106 | static inline u32 host1x_opcode_gather_nonincr(unsigned offset, unsigned count) | ||
| 107 | { | ||
| 108 | return (6 << 28) | (offset << 16) | BIT(15) | count; | ||
| 109 | } | ||
| 110 | |||
| 111 | static inline u32 host1x_opcode_gather_incr(unsigned offset, unsigned count) | ||
| 112 | { | ||
| 113 | return (6 << 28) | (offset << 16) | BIT(15) | BIT(14) | count; | ||
| 114 | } | ||
| 115 | |||
| 116 | static inline u32 host1x_opcode_acquire_mlock(unsigned id) | ||
| 117 | { | ||
| 118 | return (14 << 28) | id; | ||
| 119 | } | ||
| 120 | |||
| 121 | static inline u32 host1x_opcode_release_mlock(unsigned id) | ||
| 122 | { | ||
| 123 | return (14 << 28) | (1 << 24) | id; | ||
| 124 | } | ||
| 125 | |||
| 126 | #define HOST1X_OPCODE_NOP host1x_opcode_nonincr(0, 0) | ||
| 127 | |||
| 128 | #endif | ||
diff --git a/drivers/gpu/host1x/hw/hw_host1x05_channel.h b/drivers/gpu/host1x/hw/hw_host1x05_channel.h new file mode 100644 index 000000000..8c3499f91 --- /dev/null +++ b/drivers/gpu/host1x/hw/hw_host1x05_channel.h | |||
| @@ -0,0 +1,169 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | /* | ||
| 19 | * Function naming determines intended use: | ||
| 20 | * | ||
| 21 | * <x>_r(void) : Returns the offset for register <x>. | ||
| 22 | * | ||
| 23 | * <x>_w(void) : Returns the word offset for word (4 byte) element <x>. | ||
| 24 | * | ||
| 25 | * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits. | ||
| 26 | * | ||
| 27 | * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted | ||
| 28 | * and masked to place it at field <y> of register <x>. This value | ||
| 29 | * can be |'d with others to produce a full register value for | ||
| 30 | * register <x>. | ||
| 31 | * | ||
| 32 | * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This | ||
| 33 | * value can be ~'d and then &'d to clear the value of field <y> for | ||
| 34 | * register <x>. | ||
| 35 | * | ||
| 36 | * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted | ||
| 37 | * to place it at field <y> of register <x>. This value can be |'d | ||
| 38 | * with others to produce a full register value for <x>. | ||
| 39 | * | ||
| 40 | * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register | ||
| 41 | * <x> value 'r' after being shifted to place its LSB at bit 0. | ||
| 42 | * This value is suitable for direct comparison with other unshifted | ||
| 43 | * values appropriate for use in field <y> of register <x>. | ||
| 44 | * | ||
| 45 | * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for | ||
| 46 | * field <y> of register <x>. This value is suitable for direct | ||
| 47 | * comparison with unshifted values appropriate for use in field <y> | ||
| 48 | * of register <x>. | ||
| 49 | */ | ||
| 50 | |||
| 51 | #ifndef HOST1X_HW_HOST1X05_CHANNEL_H | ||
| 52 | #define HOST1X_HW_HOST1X05_CHANNEL_H | ||
| 53 | |||
| 54 | static inline u32 host1x_channel_ch_aperture_start_r(void) | ||
| 55 | { | ||
| 56 | return 0x10000; | ||
| 57 | } | ||
| 58 | #define HOST1X_CHANNEL_CH_APERTURE_START \ | ||
| 59 | host1x_channel_ch_aperture_start_r() | ||
| 60 | static inline u32 host1x_channel_ch_aperture_size_r(void) | ||
| 61 | { | ||
| 62 | return 0x100; | ||
| 63 | } | ||
| 64 | #define HOST1X_CHANNEL_CH_APERTURE_SIZE \ | ||
| 65 | host1x_channel_ch_aperture_size_r() | ||
| 66 | static inline u32 host1x_channel_fifostat_r(void) | ||
| 67 | { | ||
| 68 | return 0x24; | ||
| 69 | } | ||
| 70 | #define HOST1X_CHANNEL_FIFOSTAT \ | ||
| 71 | host1x_channel_fifostat_r() | ||
| 72 | static inline u32 host1x_channel_fifostat_cfempty_v(u32 r) | ||
| 73 | { | ||
| 74 | return (r >> 13) & 0x1; | ||
| 75 | } | ||
| 76 | #define HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_V(r) \ | ||
| 77 | host1x_channel_fifostat_cfempty_v(r) | ||
| 78 | static inline u32 host1x_channel_rdata_r(void) | ||
| 79 | { | ||
| 80 | return 0x28; | ||
| 81 | } | ||
| 82 | #define HOST1X_CHANNEL_RDATA \ | ||
| 83 | host1x_channel_rdata_r() | ||
| 84 | static inline u32 host1x_channel_cmdp_offset_r(void) | ||
| 85 | { | ||
| 86 | return 0x30; | ||
| 87 | } | ||
| 88 | #define HOST1X_CHANNEL_CMDP_OFFSET \ | ||
| 89 | host1x_channel_cmdp_offset_r() | ||
| 90 | static inline u32 host1x_channel_cmdp_class_r(void) | ||
| 91 | { | ||
| 92 | return 0x34; | ||
| 93 | } | ||
| 94 | #define HOST1X_CHANNEL_CMDP_CLASS \ | ||
| 95 | host1x_channel_cmdp_class_r() | ||
| 96 | static inline u32 host1x_channel_cmdp_channelstat_r(void) | ||
| 97 | { | ||
| 98 | return 0x38; | ||
| 99 | } | ||
| 100 | #define HOST1X_CHANNEL_CMDP_CHANNELSTAT \ | ||
| 101 | host1x_channel_cmdp_channelstat_r() | ||
| 102 | static inline u32 host1x_channel_dmastart_r(void) | ||
| 103 | { | ||
| 104 | return 0x0; | ||
| 105 | } | ||
| 106 | #define HOST1X_CHANNEL_DMASTART \ | ||
| 107 | host1x_channel_dmastart_r() | ||
| 108 | static inline u32 host1x_channel_dmaput_r(void) | ||
| 109 | { | ||
| 110 | return 0x8; | ||
| 111 | } | ||
| 112 | #define HOST1X_CHANNEL_DMAPUT \ | ||
| 113 | host1x_channel_dmaput_r() | ||
| 114 | static inline u32 host1x_channel_dmaget_r(void) | ||
| 115 | { | ||
| 116 | return 0x10; | ||
| 117 | } | ||
| 118 | #define HOST1X_CHANNEL_DMAGET \ | ||
| 119 | host1x_channel_dmaget_r() | ||
| 120 | static inline u32 host1x_channel_dmaend_r(void) | ||
| 121 | { | ||
| 122 | return 0x18; | ||
| 123 | } | ||
| 124 | #define HOST1X_CHANNEL_DMAEND \ | ||
| 125 | host1x_channel_dmaend_r() | ||
| 126 | static inline u32 host1x_channel_dmactrl_r(void) | ||
| 127 | { | ||
| 128 | return 0x20; | ||
| 129 | } | ||
| 130 | #define HOST1X_CHANNEL_DMACTRL \ | ||
| 131 | host1x_channel_dmactrl_r() | ||
| 132 | static inline u32 host1x_channel_dmactrl_dmastop(void) | ||
| 133 | { | ||
| 134 | return 1 << 0; | ||
| 135 | } | ||
| 136 | #define HOST1X_CHANNEL_DMACTRL_DMASTOP \ | ||
| 137 | host1x_channel_dmactrl_dmastop() | ||
| 138 | static inline u32 host1x_channel_dmactrl_dmastop_v(u32 r) | ||
| 139 | { | ||
| 140 | return (r >> 0) & 0x1; | ||
| 141 | } | ||
| 142 | #define HOST1X_CHANNEL_DMACTRL_DMASTOP_V(r) \ | ||
| 143 | host1x_channel_dmactrl_dmastop_v(r) | ||
| 144 | static inline u32 host1x_channel_dmactrl_dmagetrst(void) | ||
| 145 | { | ||
| 146 | return 1 << 1; | ||
| 147 | } | ||
| 148 | #define HOST1X_CHANNEL_DMACTRL_DMAGETRST \ | ||
| 149 | host1x_channel_dmactrl_dmagetrst() | ||
| 150 | static inline u32 host1x_channel_dmactrl_dmainitget(void) | ||
| 151 | { | ||
| 152 | return 1 << 2; | ||
| 153 | } | ||
| 154 | #define HOST1X_CHANNEL_DMACTRL_DMAINITGET \ | ||
| 155 | host1x_channel_dmactrl_dmainitget() | ||
| 156 | static inline u32 host1x_channel_smmu_streamid_r(void) | ||
| 157 | { | ||
| 158 | return 0x84; | ||
| 159 | } | ||
| 160 | #define HOST1X_CHANNEL_SMMU_STREAMID \ | ||
| 161 | host1x_channel_smmu_streamid_r() | ||
| 162 | static inline u32 host1x_channel_filter_gbuffer_r(void) | ||
| 163 | { | ||
| 164 | return 0x2020; | ||
| 165 | } | ||
| 166 | #define HOST1X_CHANNEL_FILTER_GBUFFER \ | ||
| 167 | host1x_channel_filter_gbuffer_r() | ||
| 168 | |||
| 169 | #endif | ||
diff --git a/drivers/gpu/host1x/hw/hw_host1x05_sync.h b/drivers/gpu/host1x/hw/hw_host1x05_sync.h new file mode 100644 index 000000000..55fe98859 --- /dev/null +++ b/drivers/gpu/host1x/hw/hw_host1x05_sync.h | |||
| @@ -0,0 +1,321 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | /* | ||
| 19 | * Function naming determines intended use: | ||
| 20 | * | ||
| 21 | * <x>_r(void) : Returns the offset for register <x>. | ||
| 22 | * | ||
| 23 | * <x>_w(void) : Returns the word offset for word (4 byte) element <x>. | ||
| 24 | * | ||
| 25 | * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits. | ||
| 26 | * | ||
| 27 | * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted | ||
| 28 | * and masked to place it at field <y> of register <x>. This value | ||
| 29 | * can be |'d with others to produce a full register value for | ||
| 30 | * register <x>. | ||
| 31 | * | ||
| 32 | * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This | ||
| 33 | * value can be ~'d and then &'d to clear the value of field <y> for | ||
| 34 | * register <x>. | ||
| 35 | * | ||
| 36 | * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted | ||
| 37 | * to place it at field <y> of register <x>. This value can be |'d | ||
| 38 | * with others to produce a full register value for <x>. | ||
| 39 | * | ||
| 40 | * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register | ||
| 41 | * <x> value 'r' after being shifted to place its LSB at bit 0. | ||
| 42 | * This value is suitable for direct comparison with other unshifted | ||
| 43 | * values appropriate for use in field <y> of register <x>. | ||
| 44 | * | ||
| 45 | * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for | ||
| 46 | * field <y> of register <x>. This value is suitable for direct | ||
| 47 | * comparison with unshifted values appropriate for use in field <y> | ||
| 48 | * of register <x>. | ||
| 49 | */ | ||
| 50 | |||
| 51 | #ifndef HOST1X_HW_HOST1X05_SYNC_H | ||
| 52 | #define HOST1X_HW_HOST1X05_SYNC_H | ||
| 53 | |||
| 54 | #define REGISTER_STRIDE 4 | ||
| 55 | |||
| 56 | static inline u32 host1x_sync_intstatus_r(void) | ||
| 57 | { | ||
| 58 | return 0x1c; | ||
| 59 | } | ||
| 60 | #define HOST1X_SYNC_INTSTATUS \ | ||
| 61 | host1x_sync_intstatus_r() | ||
| 62 | static inline u32 host1x_sync_intmask_r(void) | ||
| 63 | { | ||
| 64 | return 0x30; | ||
| 65 | } | ||
| 66 | #define HOST1X_SYNC_INTMASK \ | ||
| 67 | host1x_sync_intmask_r() | ||
| 68 | static inline u32 host1x_sync_intc0mask_r(void) | ||
| 69 | { | ||
| 70 | return 0x4; | ||
| 71 | } | ||
| 72 | #define HOST1X_SYNC_INTC0MASK \ | ||
| 73 | host1x_sync_intc0mask_r() | ||
| 74 | static inline u32 host1x_sync_intgmask_r(void) | ||
| 75 | { | ||
| 76 | return 0x44; | ||
| 77 | } | ||
| 78 | #define HOST1X_SYNC_INTGMASK \ | ||
| 79 | host1x_sync_intgmask_r() | ||
| 80 | static inline u32 host1x_sync_syncpt_intgmask_r(void) | ||
| 81 | { | ||
| 82 | return 0x50; | ||
| 83 | } | ||
| 84 | #define HOST1X_SYNC_SYNCPT_INTGMASK \ | ||
| 85 | host1x_sync_syncpt_intgmask_r() | ||
| 86 | static inline u32 host1x_sync_intstatus_ip_read_int_v(u32 r) | ||
| 87 | { | ||
| 88 | return (r >> 0) & 0x1; | ||
| 89 | } | ||
| 90 | #define HOST1X_SYNC_INTSTATUS_IP_READ_INT_V(r) \ | ||
| 91 | host1x_sync_intstatus_ip_read_int_v(r) | ||
| 92 | static inline u32 host1x_sync_intstatus_ip_write_int_v(u32 r) | ||
| 93 | { | ||
| 94 | return (r >> 1) & 0x1; | ||
| 95 | } | ||
| 96 | #define HOST1X_SYNC_INTSTATUS_IP_WRITE_INT_V(r) \ | ||
| 97 | host1x_sync_intstatus_ip_write_int_v(r) | ||
| 98 | static inline u32 host1x_sync_intstatus_illegal_pb_access_v(u32 r) | ||
| 99 | { | ||
| 100 | return (r >> 28) & 0x1; | ||
| 101 | } | ||
| 102 | #define HOST1X_SYNC_INTSTATUS_ILLEGAL_PB_ACCESS_V(r) \ | ||
| 103 | host1x_sync_intstatus_illegal_pb_access_v(r) | ||
| 104 | static inline u32 host1x_sync_illegal_syncpt_access_frm_pb_r(void) | ||
| 105 | { | ||
| 106 | return 0x2270; | ||
| 107 | } | ||
| 108 | #define HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_PB \ | ||
| 109 | host1x_sync_illegal_syncpt_access_frm_pb_r() | ||
| 110 | static inline u32 host1x_sync_illegal_syncpt_access_frm_pb_syncpt_v(u32 r) | ||
| 111 | { | ||
| 112 | return (r >> 16) & 0x3ff; | ||
| 113 | } | ||
| 114 | #define HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_PB_SYNCPT_V(r) \ | ||
| 115 | host1x_sync_illegal_syncpt_access_frm_pb_syncpt_v(r) | ||
| 116 | static inline u32 host1x_sync_illegal_syncpt_access_frm_pb_ch_v(u32 r) | ||
| 117 | { | ||
| 118 | return (r >> 10) & 0x3f; | ||
| 119 | } | ||
| 120 | #define HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_PB_CH_V(r) \ | ||
| 121 | host1x_sync_illegal_syncpt_access_frm_pb_ch_v(r) | ||
| 122 | static inline u32 host1x_sync_intstatus_illegal_client_access_v(u32 r) | ||
| 123 | { | ||
| 124 | return (r >> 30) & 0x1; | ||
| 125 | } | ||
| 126 | #define HOST1X_SYNC_INTSTATUS_ILLEGAL_CLIENT_ACCESS_V(r) \ | ||
| 127 | host1x_sync_intstatus_illegal_client_access_v(r) | ||
| 128 | static inline u32 host1x_sync_illegal_syncpt_access_frm_client_r(void) | ||
| 129 | { | ||
| 130 | return 0x2268; | ||
| 131 | } | ||
| 132 | #define HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_CLIENT \ | ||
| 133 | host1x_sync_illegal_syncpt_access_frm_client_r() | ||
| 134 | static inline u32 host1x_sync_illegal_syncpt_access_frm_client_syncpt_v(u32 r) | ||
| 135 | { | ||
| 136 | return (r >> 16) & 0x3ff; | ||
| 137 | } | ||
| 138 | #define HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_CLIENT_SYNCPT_V(r) \ | ||
| 139 | host1x_sync_illegal_syncpt_access_frm_client_syncpt_v(r) | ||
| 140 | static inline u32 host1x_sync_illegal_syncpt_access_frm_client_ch_v(u32 r) | ||
| 141 | { | ||
| 142 | return (r >> 10) & 0x3f; | ||
| 143 | } | ||
| 144 | #define HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_CLIENT_CH_V(r) \ | ||
| 145 | host1x_sync_illegal_syncpt_access_frm_client_ch_v(r) | ||
| 146 | static inline u32 host1x_sync_syncpt_r(unsigned int id) | ||
| 147 | { | ||
| 148 | return 0x18080 + id * REGISTER_STRIDE; | ||
| 149 | } | ||
| 150 | #define HOST1X_SYNC_SYNCPT(id) \ | ||
| 151 | host1x_sync_syncpt_r(id) | ||
| 152 | static inline u32 host1x_sync_syncpt_thresh_cpu0_int_status_r(unsigned int id) | ||
| 153 | { | ||
| 154 | return 0x16464 + id * REGISTER_STRIDE; | ||
| 155 | } | ||
| 156 | #define HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(id) \ | ||
| 157 | host1x_sync_syncpt_thresh_cpu0_int_status_r(id) | ||
| 158 | static inline u32 host1x_sync_syncpt_thresh_int_disable_r(unsigned int id) | ||
| 159 | { | ||
| 160 | return 0x16590 + id * REGISTER_STRIDE; | ||
| 161 | } | ||
| 162 | #define HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(id) \ | ||
| 163 | host1x_sync_syncpt_thresh_int_disable_r(id) | ||
| 164 | static inline u32 host1x_sync_syncpt_thresh_int_enable_cpu0_r(unsigned int id) | ||
| 165 | { | ||
| 166 | return 0x1652c + id * REGISTER_STRIDE; | ||
| 167 | } | ||
| 168 | #define HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(id) \ | ||
| 169 | host1x_sync_syncpt_thresh_int_enable_cpu0_r(id) | ||
| 170 | static inline u32 host1x_sync_cf_setup_r(unsigned int channel) | ||
| 171 | { | ||
| 172 | return 0x2588 + channel * REGISTER_STRIDE; | ||
| 173 | } | ||
| 174 | #define HOST1X_SYNC_CF_SETUP(channel) \ | ||
| 175 | host1x_sync_cf_setup_r(channel) | ||
| 176 | static inline u32 host1x_sync_cf_setup_base_v(u32 r) | ||
| 177 | { | ||
| 178 | return (r >> 0) & 0xfff; | ||
| 179 | } | ||
| 180 | #define HOST1X_SYNC_CF_SETUP_BASE_V(r) \ | ||
| 181 | host1x_sync_cf_setup_base_v(r) | ||
| 182 | static inline u32 host1x_sync_cf_setup_limit_v(u32 r) | ||
| 183 | { | ||
| 184 | return (r >> 16) & 0xfff; | ||
| 185 | } | ||
| 186 | #define HOST1X_SYNC_CF_SETUP_LIMIT_V(r) \ | ||
| 187 | host1x_sync_cf_setup_limit_v(r) | ||
| 188 | static inline u32 host1x_sync_cmdproc_stop_r(void) | ||
| 189 | { | ||
| 190 | return 0x48; | ||
| 191 | } | ||
| 192 | #define HOST1X_SYNC_CMDPROC_STOP \ | ||
| 193 | host1x_sync_cmdproc_stop_r() | ||
| 194 | static inline u32 host1x_sync_ch_teardown_r(void) | ||
| 195 | { | ||
| 196 | return 0x4c; | ||
| 197 | } | ||
| 198 | #define HOST1X_SYNC_CH_TEARDOWN \ | ||
| 199 | host1x_sync_ch_teardown_r() | ||
| 200 | static inline u32 host1x_sync_usec_clk_r(void) | ||
| 201 | { | ||
| 202 | return 0x2244; | ||
| 203 | } | ||
| 204 | #define HOST1X_SYNC_USEC_CLK \ | ||
| 205 | host1x_sync_usec_clk_r() | ||
| 206 | static inline u32 host1x_sync_ctxsw_timeout_cfg_r(void) | ||
| 207 | { | ||
| 208 | return 0x2248; | ||
| 209 | } | ||
| 210 | #define HOST1X_SYNC_CTXSW_TIMEOUT_CFG \ | ||
| 211 | host1x_sync_ctxsw_timeout_cfg_r() | ||
| 212 | static inline u32 host1x_sync_ip_busy_timeout_r(void) | ||
| 213 | { | ||
| 214 | return 0x2250; | ||
| 215 | } | ||
| 216 | #define HOST1X_SYNC_IP_BUSY_TIMEOUT \ | ||
| 217 | host1x_sync_ip_busy_timeout_r() | ||
| 218 | static inline u32 host1x_sync_ip_read_timeout_addr_r(void) | ||
| 219 | { | ||
| 220 | return 0x2254; | ||
| 221 | } | ||
| 222 | #define HOST1X_SYNC_IP_READ_TIMEOUT_ADDR \ | ||
| 223 | host1x_sync_ip_read_timeout_addr_r() | ||
| 224 | static inline u32 host1x_sync_ip_write_timeout_addr_r(void) | ||
| 225 | { | ||
| 226 | return 0x225c; | ||
| 227 | } | ||
| 228 | #define HOST1X_SYNC_IP_WRITE_TIMEOUT_ADDR \ | ||
| 229 | host1x_sync_ip_write_timeout_addr_r() | ||
| 230 | static inline u32 host1x_sync_syncpt_int_thresh_r(unsigned int id) | ||
| 231 | { | ||
| 232 | return 0x18a00 + id * REGISTER_STRIDE; | ||
| 233 | } | ||
| 234 | #define HOST1X_SYNC_SYNCPT_INT_THRESH(id) \ | ||
| 235 | host1x_sync_syncpt_int_thresh_r(id) | ||
| 236 | static inline u32 host1x_sync_syncpt_base_r(unsigned int id) | ||
| 237 | { | ||
| 238 | return 0x18000 + id * REGISTER_STRIDE; | ||
| 239 | } | ||
| 240 | #define HOST1X_SYNC_SYNCPT_BASE(id) \ | ||
| 241 | host1x_sync_syncpt_base_r(id) | ||
| 242 | static inline u32 host1x_sync_syncpt_cpu_incr_r(unsigned int id) | ||
| 243 | { | ||
| 244 | return 0x16400 + id * REGISTER_STRIDE; | ||
| 245 | } | ||
| 246 | #define HOST1X_SYNC_SYNCPT_CPU_INCR(id) \ | ||
| 247 | host1x_sync_syncpt_cpu_incr_r(id) | ||
| 248 | static inline u32 host1x_sync_cfpeek_ctrl_r(void) | ||
| 249 | { | ||
| 250 | return 0x233c; | ||
| 251 | } | ||
| 252 | #define HOST1X_SYNC_CFPEEK_CTRL \ | ||
| 253 | host1x_sync_cfpeek_ctrl_r() | ||
| 254 | static inline u32 host1x_sync_cfpeek_ctrl_addr_f(u32 v) | ||
| 255 | { | ||
| 256 | return (v & 0xfff) << 0; | ||
| 257 | } | ||
| 258 | #define HOST1X_SYNC_CFPEEK_CTRL_ADDR_F(v) \ | ||
| 259 | host1x_sync_cfpeek_ctrl_addr_f(v) | ||
| 260 | static inline u32 host1x_sync_cfpeek_ctrl_channr_f(u32 v) | ||
| 261 | { | ||
| 262 | return (v & 0x3f) << 16; | ||
| 263 | } | ||
| 264 | #define HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(v) \ | ||
| 265 | host1x_sync_cfpeek_ctrl_channr_f(v) | ||
| 266 | static inline u32 host1x_sync_cfpeek_ctrl_ena_f(u32 v) | ||
| 267 | { | ||
| 268 | return (v & 0x1) << 31; | ||
| 269 | } | ||
| 270 | #define HOST1X_SYNC_CFPEEK_CTRL_ENA_F(v) \ | ||
| 271 | host1x_sync_cfpeek_ctrl_ena_f(v) | ||
| 272 | static inline u32 host1x_sync_cfpeek_read_r(void) | ||
| 273 | { | ||
| 274 | return 0x2340; | ||
| 275 | } | ||
| 276 | #define HOST1X_SYNC_CFPEEK_READ \ | ||
| 277 | host1x_sync_cfpeek_read_r() | ||
| 278 | static inline u32 host1x_sync_cfpeek_ptrs_r(void) | ||
| 279 | { | ||
| 280 | return 0x2344; | ||
| 281 | } | ||
| 282 | #define HOST1X_SYNC_CFPEEK_PTRS \ | ||
| 283 | host1x_sync_cfpeek_ptrs_r() | ||
| 284 | static inline u32 host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(u32 r) | ||
| 285 | { | ||
| 286 | return (r >> 0) & 0xfff; | ||
| 287 | } | ||
| 288 | #define HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_V(r) \ | ||
| 289 | host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(r) | ||
| 290 | static inline u32 host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(u32 r) | ||
| 291 | { | ||
| 292 | return (r >> 16) & 0xfff; | ||
| 293 | } | ||
| 294 | #define HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_V(r) \ | ||
| 295 | host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(r) | ||
| 296 | static inline u32 host1x_sync_common_mlock_r(unsigned long id) | ||
| 297 | { | ||
| 298 | return 0x2030 + id * REGISTER_STRIDE; | ||
| 299 | } | ||
| 300 | #define HOST1X_SYNC_COMMON_MLOCK \ | ||
| 301 | host1x_sync_common_mlock_r() | ||
| 302 | static inline u32 host1x_sync_common_mlock_ch_v(u32 r) | ||
| 303 | { | ||
| 304 | return (r >> 2) & 0x3f; | ||
| 305 | } | ||
| 306 | #define HOST1X_SYNC_COMMON_MLOCK_CH_V(r) \ | ||
| 307 | host1x_sync_common_mlock_ch_v(r) | ||
| 308 | static inline u32 host1x_sync_common_mlock_locked_v(u32 r) | ||
| 309 | { | ||
| 310 | return (r >> 0) & 0x1; | ||
| 311 | } | ||
| 312 | #define HOST1X_SYNC_COMMON_MLOCK_LOCKED_V(r) \ | ||
| 313 | host1x_sync_common_mlock_locked_v(r) | ||
| 314 | static inline u32 host1x_thost_common_icg_en_override_0_r(void) | ||
| 315 | { | ||
| 316 | return 0x2aa8; | ||
| 317 | } | ||
| 318 | #define HOST1X_THOST_COMMON_ICG_EN_OVERRIDE_0 \ | ||
| 319 | host1x_thost_common_icg_en_override_0_r() | ||
| 320 | |||
| 321 | #endif | ||
diff --git a/drivers/gpu/host1x/hw/hw_host1x05_uclass.h b/drivers/gpu/host1x/hw/hw_host1x05_uclass.h new file mode 100644 index 000000000..01145f610 --- /dev/null +++ b/drivers/gpu/host1x/hw/hw_host1x05_uclass.h | |||
| @@ -0,0 +1,157 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | /* | ||
| 19 | * Function naming determines intended use: | ||
| 20 | * | ||
| 21 | * <x>_r(void) : Returns the offset for register <x>. | ||
| 22 | * | ||
| 23 | * <x>_w(void) : Returns the word offset for word (4 byte) element <x>. | ||
| 24 | * | ||
| 25 | * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits. | ||
| 26 | * | ||
| 27 | * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted | ||
| 28 | * and masked to place it at field <y> of register <x>. This value | ||
| 29 | * can be |'d with others to produce a full register value for | ||
| 30 | * register <x>. | ||
| 31 | * | ||
| 32 | * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This | ||
| 33 | * value can be ~'d and then &'d to clear the value of field <y> for | ||
| 34 | * register <x>. | ||
| 35 | * | ||
| 36 | * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted | ||
| 37 | * to place it at field <y> of register <x>. This value can be |'d | ||
| 38 | * with others to produce a full register value for <x>. | ||
| 39 | * | ||
| 40 | * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register | ||
| 41 | * <x> value 'r' after being shifted to place its LSB at bit 0. | ||
| 42 | * This value is suitable for direct comparison with other unshifted | ||
| 43 | * values appropriate for use in field <y> of register <x>. | ||
| 44 | * | ||
| 45 | * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for | ||
| 46 | * field <y> of register <x>. This value is suitable for direct | ||
| 47 | * comparison with unshifted values appropriate for use in field <y> | ||
| 48 | * of register <x>. | ||
| 49 | */ | ||
| 50 | |||
| 51 | #ifndef HOST1X_HW_HOST1X05_UCLASS_H | ||
| 52 | #define HOST1X_HW_HOST1X05_UCLASS_H | ||
| 53 | |||
| 54 | static inline u32 host1x_uclass_incr_syncpt_r(void) | ||
| 55 | { | ||
| 56 | return 0x0; | ||
| 57 | } | ||
| 58 | #define HOST1X_UCLASS_INCR_SYNCPT \ | ||
| 59 | host1x_uclass_incr_syncpt_r() | ||
| 60 | static inline u32 host1x_uclass_incr_syncpt_cond_f(u32 v) | ||
| 61 | { | ||
| 62 | return (v & 0xff) << 10; | ||
| 63 | } | ||
| 64 | #define HOST1X_UCLASS_INCR_SYNCPT_COND_F(v) \ | ||
| 65 | host1x_uclass_incr_syncpt_cond_f(v) | ||
| 66 | static inline u32 host1x_uclass_incr_syncpt_indx_f(u32 v) | ||
| 67 | { | ||
| 68 | return (v & 0x3ff) << 0; | ||
| 69 | } | ||
| 70 | #define HOST1X_UCLASS_INCR_SYNCPT_INDX_F(v) \ | ||
| 71 | host1x_uclass_incr_syncpt_indx_f(v) | ||
| 72 | static inline u32 host1x_uclass_load_syncpt_payload_32_r(void) | ||
| 73 | { | ||
| 74 | return 0x4e; | ||
| 75 | } | ||
| 76 | #define HOST1X_UCLASS_LOAD_SYNCPT_PAYLOAD_32 \ | ||
| 77 | host1x_uclass_load_syncpt_payload_32_r() | ||
| 78 | static inline u32 host1x_uclass_wait_syncpt_32_r(void) | ||
| 79 | { | ||
| 80 | return 0x50; | ||
| 81 | } | ||
| 82 | #define HOST1X_UCLASS_WAIT_SYNCPT_32 \ | ||
| 83 | host1x_uclass_wait_syncpt_32_r() | ||
| 84 | static inline u32 host1x_uclass_wait_syncpt_r(void) | ||
| 85 | { | ||
| 86 | return 0x8; | ||
| 87 | } | ||
| 88 | #define HOST1X_UCLASS_WAIT_SYNCPT \ | ||
| 89 | host1x_uclass_wait_syncpt_r() | ||
| 90 | static inline u32 host1x_uclass_wait_syncpt_indx_f(u32 v) | ||
| 91 | { | ||
| 92 | return (v & 0xff) << 24; | ||
| 93 | } | ||
| 94 | #define HOST1X_UCLASS_WAIT_SYNCPT_INDX_F(v) \ | ||
| 95 | host1x_uclass_wait_syncpt_indx_f(v) | ||
| 96 | static inline u32 host1x_uclass_wait_syncpt_thresh_f(u32 v) | ||
| 97 | { | ||
| 98 | return (v & 0xffffff) << 0; | ||
| 99 | } | ||
| 100 | #define HOST1X_UCLASS_WAIT_SYNCPT_THRESH_F(v) \ | ||
| 101 | host1x_uclass_wait_syncpt_thresh_f(v) | ||
| 102 | static inline u32 host1x_uclass_wait_syncpt_base_r(void) | ||
| 103 | { | ||
| 104 | return 0x9; | ||
| 105 | } | ||
| 106 | #define HOST1X_UCLASS_WAIT_SYNCPT_BASE \ | ||
| 107 | host1x_uclass_wait_syncpt_base_r() | ||
| 108 | static inline u32 host1x_uclass_wait_syncpt_base_indx_f(u32 v) | ||
| 109 | { | ||
| 110 | return (v & 0x3ff) << 22; | ||
| 111 | } | ||
| 112 | #define HOST1X_UCLASS_WAIT_SYNCPT_BASE_INDX_F(v) \ | ||
| 113 | host1x_uclass_wait_syncpt_base_indx_f(v) | ||
| 114 | static inline u32 host1x_uclass_wait_syncpt_base_base_indx_f(u32 v) | ||
| 115 | { | ||
| 116 | return (v & 0x3f) << 16; | ||
| 117 | } | ||
| 118 | #define HOST1X_UCLASS_WAIT_SYNCPT_BASE_BASE_INDX_F(v) \ | ||
| 119 | host1x_uclass_wait_syncpt_base_base_indx_f(v) | ||
| 120 | static inline u32 host1x_uclass_wait_syncpt_base_offset_f(u32 v) | ||
| 121 | { | ||
| 122 | return (v & 0xffff) << 0; | ||
| 123 | } | ||
| 124 | #define HOST1X_UCLASS_WAIT_SYNCPT_BASE_OFFSET_F(v) \ | ||
| 125 | host1x_uclass_wait_syncpt_base_offset_f(v) | ||
| 126 | static inline u32 host1x_uclass_load_syncpt_base_r(void) | ||
| 127 | { | ||
| 128 | return 0xb; | ||
| 129 | } | ||
| 130 | #define HOST1X_UCLASS_LOAD_SYNCPT_BASE \ | ||
| 131 | host1x_uclass_load_syncpt_base_r() | ||
| 132 | static inline u32 host1x_uclass_load_syncpt_base_base_indx_f(u32 v) | ||
| 133 | { | ||
| 134 | return (v & 0xff) << 24; | ||
| 135 | } | ||
| 136 | #define HOST1X_UCLASS_LOAD_SYNCPT_BASE_BASE_INDX_F(v) \ | ||
| 137 | host1x_uclass_load_syncpt_base_base_indx_f(v) | ||
| 138 | static inline u32 host1x_uclass_load_syncpt_base_value_f(u32 v) | ||
| 139 | { | ||
| 140 | return (v & 0xffffff) << 0; | ||
| 141 | } | ||
| 142 | #define HOST1X_UCLASS_LOAD_SYNCPT_BASE_VALUE_F(v) \ | ||
| 143 | host1x_uclass_load_syncpt_base_value_f(v) | ||
| 144 | static inline u32 host1x_uclass_incr_syncpt_base_base_indx_f(u32 v) | ||
| 145 | { | ||
| 146 | return (v & 0xff) << 24; | ||
| 147 | } | ||
| 148 | #define HOST1X_UCLASS_INCR_SYNCPT_BASE_BASE_INDX_F(v) \ | ||
| 149 | host1x_uclass_incr_syncpt_base_base_indx_f(v) | ||
| 150 | static inline u32 host1x_uclass_incr_syncpt_base_offset_f(u32 v) | ||
| 151 | { | ||
| 152 | return (v & 0xffffff) << 0; | ||
| 153 | } | ||
| 154 | #define HOST1X_UCLASS_INCR_SYNCPT_BASE_OFFSET_F(v) \ | ||
| 155 | host1x_uclass_incr_syncpt_base_offset_f(v) | ||
| 156 | |||
| 157 | #endif | ||
diff --git a/drivers/gpu/host1x/hw/intr_hw_t186.c b/drivers/gpu/host1x/hw/intr_hw_t186.c new file mode 100644 index 000000000..48bd1150f --- /dev/null +++ b/drivers/gpu/host1x/hw/intr_hw_t186.c | |||
| @@ -0,0 +1,247 @@ | |||
| 1 | /* | ||
| 2 | * Tegra host1x Interrupt Management | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Google, Inc. | ||
| 5 | * Copyright (C) 2016 NVIDIA Corporation. All rights reserved. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms and conditions of the GNU General Public License, | ||
| 9 | * version 2, as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 14 | * more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/interrupt.h> | ||
| 21 | #include <linux/irq.h> | ||
| 22 | #include <linux/io.h> | ||
| 23 | |||
| 24 | #include "intr.h" | ||
| 25 | #include "dev.h" | ||
| 26 | |||
| 27 | |||
| 28 | static inline u32 bit_mask(u32 nr) | ||
| 29 | { | ||
| 30 | return 1UL << (nr % 32); | ||
| 31 | } | ||
| 32 | static inline u32 bit_word(u32 nr) | ||
| 33 | { | ||
| 34 | return nr / 32; | ||
| 35 | } | ||
| 36 | |||
| 37 | /* | ||
| 38 | * Sync point threshold interrupt service function | ||
| 39 | * Handles sync point threshold triggers, in interrupt context | ||
| 40 | */ | ||
| 41 | static void host1x_intr_syncpt_handle(struct host1x_syncpt *syncpt) | ||
| 42 | { | ||
| 43 | unsigned int id = syncpt->id; | ||
| 44 | struct host1x *host = syncpt->host; | ||
| 45 | |||
| 46 | host1x_sync_writel(host, bit_mask(id), | ||
| 47 | HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(bit_word(id))); | ||
| 48 | host1x_sync_writel(host, bit_mask(id), | ||
| 49 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(bit_word(id))); | ||
| 50 | |||
| 51 | queue_work(host->intr_wq, &syncpt->intr.work); | ||
| 52 | } | ||
| 53 | |||
| 54 | static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id) | ||
| 55 | { | ||
| 56 | struct host1x *host = dev_id; | ||
| 57 | unsigned long reg; | ||
| 58 | int i, set_bit; | ||
| 59 | |||
| 60 | for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); i++) { | ||
| 61 | reg = host1x_sync_readl(host, | ||
| 62 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i)); | ||
| 63 | for_each_set_bit(set_bit, ®, 32) { | ||
| 64 | struct host1x_syncpt *syncpt; | ||
| 65 | int id = i * 32 + set_bit; | ||
| 66 | |||
| 67 | if (unlikely(id < 0 || id >= host->info->nb_pts)) { | ||
| 68 | dev_err(host->dev, | ||
| 69 | "%s(): unexptected syncpt id %d\n", | ||
| 70 | __func__, id); | ||
| 71 | goto out; | ||
| 72 | } | ||
| 73 | syncpt = host->syncpt + id; | ||
| 74 | host1x_intr_syncpt_handle(syncpt); | ||
| 75 | } | ||
| 76 | } | ||
| 77 | out: | ||
| 78 | return IRQ_HANDLED; | ||
| 79 | } | ||
| 80 | |||
| 81 | static void _host1x_intr_disable_all_syncpt_intrs(struct host1x *host) | ||
| 82 | { | ||
| 83 | u32 i; | ||
| 84 | |||
| 85 | for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); ++i) { | ||
| 86 | host1x_sync_writel(host, 0xffffffffu, | ||
| 87 | HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(i)); | ||
| 88 | host1x_sync_writel(host, 0xffffffffu, | ||
| 89 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i)); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | static int _host1x_intr_init_host_sync(struct host1x *host, u32 cpm, | ||
| 94 | void (*syncpt_thresh_work)(struct work_struct *)) | ||
| 95 | { | ||
| 96 | int i, err; | ||
| 97 | |||
| 98 | host1x_hw_intr_disable_all_syncpt_intrs(host); | ||
| 99 | |||
| 100 | for (i = 0; i < host->info->nb_pts; i++) | ||
| 101 | INIT_WORK(&host->syncpt[i].intr.work, syncpt_thresh_work); | ||
| 102 | |||
| 103 | err = devm_request_irq(host->dev, host->intr_syncpt_irq, | ||
| 104 | syncpt_thresh_isr, IRQF_SHARED, | ||
| 105 | "host1x_syncpt", host); | ||
| 106 | if (IS_ERR_VALUE(err)) { | ||
| 107 | WARN_ON(1); | ||
| 108 | return err; | ||
| 109 | } | ||
| 110 | |||
| 111 | /* disable the ip_busy_timeout. this prevents write drops */ | ||
| 112 | host1x_sync_writel(host, 0, HOST1X_SYNC_IP_BUSY_TIMEOUT); | ||
| 113 | |||
| 114 | /* | ||
| 115 | * increase the auto-ack timout to the maximum value. 2d will hang | ||
| 116 | * otherwise on Tegra2. | ||
| 117 | */ | ||
| 118 | host1x_sync_writel(host, 0xff, HOST1X_SYNC_CTXSW_TIMEOUT_CFG); | ||
| 119 | |||
| 120 | /* update host clocks per usec */ | ||
| 121 | host1x_sync_writel(host, cpm, HOST1X_SYNC_USEC_CLK); | ||
| 122 | |||
| 123 | return 0; | ||
| 124 | } | ||
| 125 | |||
| 126 | static void _host1x_intr_set_syncpt_threshold(struct host1x *host, | ||
| 127 | u32 id, u32 thresh) | ||
| 128 | { | ||
| 129 | host1x_sync_writel(host, thresh, HOST1X_SYNC_SYNCPT_INT_THRESH(id)); | ||
| 130 | } | ||
| 131 | |||
| 132 | static void _host1x_intr_enable_syncpt_intr(struct host1x *host, u32 id) | ||
| 133 | { | ||
| 134 | host1x_sync_writel(host, bit_mask(id), | ||
| 135 | HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(bit_word(id))); | ||
| 136 | } | ||
| 137 | |||
| 138 | static void _host1x_intr_disable_syncpt_intr(struct host1x *host, u32 id) | ||
| 139 | { | ||
| 140 | host1x_sync_writel(host, bit_mask(id), | ||
| 141 | HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(bit_word(id))); | ||
| 142 | host1x_sync_writel(host, bit_mask(id), | ||
| 143 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(bit_word(id))); | ||
| 144 | } | ||
| 145 | |||
| 146 | static int _host1x_free_syncpt_irq(struct host1x *host) | ||
| 147 | { | ||
| 148 | devm_free_irq(host->dev, host->intr_syncpt_irq, host); | ||
| 149 | flush_workqueue(host->intr_wq); | ||
| 150 | return 0; | ||
| 151 | } | ||
| 152 | |||
| 153 | /** | ||
| 154 | * Host general interrupt service function | ||
| 155 | * Handles read / write failures | ||
| 156 | */ | ||
| 157 | static irqreturn_t general_isr(int irq, void *dev_id) | ||
| 158 | { | ||
| 159 | struct host1x *host = dev_id; | ||
| 160 | u32 intstatus, addr; | ||
| 161 | |||
| 162 | /* Handle host1x interrupt in ISR */ | ||
| 163 | intstatus = host1x_sync_readl(host, HOST1X_SYNC_INTSTATUS); | ||
| 164 | |||
| 165 | if (HOST1X_SYNC_INTSTATUS_IP_READ_INT_V(intstatus)) { | ||
| 166 | addr = host1x_sync_readl(host, | ||
| 167 | HOST1X_SYNC_IP_READ_TIMEOUT_ADDR); | ||
| 168 | pr_err("Host read timeout at address %x\n", addr); | ||
| 169 | } | ||
| 170 | |||
| 171 | if (HOST1X_SYNC_INTSTATUS_IP_WRITE_INT_V(intstatus)) { | ||
| 172 | addr = host1x_sync_readl(host, | ||
| 173 | HOST1X_SYNC_IP_WRITE_TIMEOUT_ADDR); | ||
| 174 | pr_err("Host write timeout at address %x\n", addr); | ||
| 175 | } | ||
| 176 | |||
| 177 | if (HOST1X_SYNC_INTSTATUS_ILLEGAL_PB_ACCESS_V(intstatus)) { | ||
| 178 | u32 stat = host1x_sync_readl(host, HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_PB); | ||
| 179 | u32 ch = HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_PB_CH_V(stat); | ||
| 180 | u32 id = HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_PB_SYNCPT_V(stat); | ||
| 181 | pr_err("Host illegal syncpoint pb access (ch=%u, id=%u)\n", ch, id); | ||
| 182 | } | ||
| 183 | |||
| 184 | if (HOST1X_SYNC_INTSTATUS_ILLEGAL_CLIENT_ACCESS_V(intstatus)) { | ||
| 185 | u32 stat = host1x_sync_readl(host, HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_CLIENT); | ||
| 186 | u32 ch = HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_CLIENT_CH_V(stat); | ||
| 187 | u32 id = HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_CLIENT_SYNCPT_V(stat); | ||
| 188 | pr_err("Host illegal syncpoint client access (ch=%u, id=%u)\n", ch, id); | ||
| 189 | } | ||
| 190 | |||
| 191 | host1x_sync_writel(host, intstatus, HOST1X_SYNC_INTSTATUS); | ||
| 192 | |||
| 193 | return IRQ_HANDLED; | ||
| 194 | } | ||
| 195 | |||
| 196 | static int _host1x_intr_request_host_general_irq(struct host1x *host) | ||
| 197 | { | ||
| 198 | int err; | ||
| 199 | |||
| 200 | /* master disable for general (not syncpt) host interrupts */ | ||
| 201 | host1x_sync_writel(host, 0, HOST1X_SYNC_INTC0MASK); | ||
| 202 | host1x_sync_writel(host, 0, HOST1X_SYNC_INTGMASK); | ||
| 203 | host1x_sync_writel(host, 0, HOST1X_SYNC_INTMASK); | ||
| 204 | |||
| 205 | err = devm_request_irq(host->dev, host->intr_general_irq, | ||
| 206 | general_isr, 0, | ||
| 207 | "host1x_general", host); | ||
| 208 | if (IS_ERR_VALUE(err)) { | ||
| 209 | WARN_ON(1); | ||
| 210 | return err; | ||
| 211 | } | ||
| 212 | |||
| 213 | /* enable host module interrupt to CPU0 */ | ||
| 214 | host1x_sync_writel(host, BIT(0), HOST1X_SYNC_INTC0MASK); | ||
| 215 | host1x_sync_writel(host, BIT(0), HOST1X_SYNC_INTGMASK); | ||
| 216 | host1x_sync_writel(host, 0xff << 8, HOST1X_SYNC_SYNCPT_INTGMASK); | ||
| 217 | |||
| 218 | /* master enable for general (not syncpt) host interrupts | ||
| 219 | * (AXIREAD, AXIWRITE, Syncpoint protection */ | ||
| 220 | host1x_sync_writel(host, BIT(0) | BIT(1) | BIT(28) | BIT(30), | ||
| 221 | HOST1X_SYNC_INTMASK); | ||
| 222 | |||
| 223 | return err; | ||
| 224 | } | ||
| 225 | |||
| 226 | static void _host1x_intr_free_host_general_irq(struct host1x *host) | ||
| 227 | { | ||
| 228 | /* master disable for general (not syncpt) host interrupts */ | ||
| 229 | host1x_sync_writel(host, 0, HOST1X_SYNC_INTMASK); | ||
| 230 | host1x_sync_writel(host, 0, HOST1X_SYNC_SYNCPT_INTGMASK); | ||
| 231 | |||
| 232 | devm_free_irq(host->dev, host->intr_general_irq, host); | ||
| 233 | } | ||
| 234 | |||
| 235 | static const struct host1x_intr_ops host1x_intr_t186_ops = { | ||
| 236 | /* Syncpt interrupts */ | ||
| 237 | .init_host_sync = _host1x_intr_init_host_sync, | ||
| 238 | .set_syncpt_threshold = _host1x_intr_set_syncpt_threshold, | ||
| 239 | .enable_syncpt_intr = _host1x_intr_enable_syncpt_intr, | ||
| 240 | .disable_syncpt_intr = _host1x_intr_disable_syncpt_intr, | ||
| 241 | .disable_all_syncpt_intrs = _host1x_intr_disable_all_syncpt_intrs, | ||
| 242 | .free_syncpt_irq = _host1x_free_syncpt_irq, | ||
| 243 | |||
| 244 | /* Host general interrupts */ | ||
| 245 | .request_host_general_irq = _host1x_intr_request_host_general_irq, | ||
| 246 | .free_host_general_irq = _host1x_intr_free_host_general_irq, | ||
| 247 | }; | ||
diff --git a/drivers/gpu/host1x/hw/stremid_hw_t186.c b/drivers/gpu/host1x/hw/stremid_hw_t186.c new file mode 100644 index 000000000..9f4c36852 --- /dev/null +++ b/drivers/gpu/host1x/hw/stremid_hw_t186.c | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2016, NVIDIA Corporation. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | |||
| 18 | #include "dev_t186.h" | ||
| 19 | |||
| 20 | struct host1x_streamid_mapping { | ||
| 21 | u32 host1x_offset; | ||
| 22 | u32 client_offset; | ||
| 23 | u32 client_limit; | ||
| 24 | }; | ||
| 25 | |||
| 26 | static struct host1x_streamid_mapping __attribute__((__unused__)) | ||
| 27 | t18x_host1x_streamid_mapping[] = { | ||
| 28 | /* HOST1X_THOST_COMMON_SE1_STRMID_0_OFFSET_BASE_0 */ | ||
| 29 | { 0x00001ac8, 0x00000090, 0x00000090}, | ||
| 30 | /* HOST1X_THOST_COMMON_SE2_STRMID_0_OFFSET_BASE_0 */ | ||
| 31 | { 0x00001ad0, 0x00000090, 0x00000090}, | ||
| 32 | /* HOST1X_THOST_COMMON_SE3_STRMID_0_OFFSET_BASE_0 */ | ||
| 33 | { 0x00001ad8, 0x00000090, 0x00000090}, | ||
| 34 | /* HOST1X_THOST_COMMON_SE4_STRMID_0_OFFSET_BASE_0 */ | ||
| 35 | { 0x00001ae0, 0x00000090, 0x00000090}, | ||
| 36 | /* HOST1X_THOST_COMMON_ISP_STRMID_0_OFFSET_BASE_0 */ | ||
| 37 | { 0x00001ae8, 0x00000050, 0x00000050}, | ||
| 38 | /* HOST1X_THOST_COMMON_VIC_STRMID_0_OFFSET_BASE_0 */ | ||
| 39 | { 0x00001af0, 0x00000030, 0x00000034}, | ||
| 40 | /* HOST1X_THOST_COMMON_NVENC_STRMID_0_OFFSET_BASE_0 */ | ||
| 41 | { 0x00001af8, 0x00000030, 0x00000034}, | ||
| 42 | /* HOST1X_THOST_COMMON_NVDEC_STRMID_0_OFFSET_BASE_0 */ | ||
| 43 | { 0x00001b00, 0x00000030, 0x00000034}, | ||
| 44 | /* HOST1X_THOST_COMMON_NVJPG_STRMID_0_OFFSET_BASE_0 */ | ||
| 45 | { 0x00001b08, 0x00000030, 0x00000034}, | ||
| 46 | /* HOST1X_THOST_COMMON_TSEC_STRMID_0_OFFSET_BASE_0 */ | ||
| 47 | { 0x00001b10, 0x00000030, 0x00000034}, | ||
| 48 | /* HOST1X_THOST_COMMON_TSECB_STRMID_0_OFFSET_BASE_0 */ | ||
| 49 | { 0x00001b18, 0x00000030, 0x00000034}, | ||
| 50 | /* HOST1X_THOST_COMMON_VI_STRMID_0_OFFSET_BASE_0 */ | ||
| 51 | { 0x00001b80, 0x00010000, 0x00010000}, | ||
| 52 | /* HOST1X_THOST_COMMON_VI_STRMID_1_OFFSET_BASE_0 */ | ||
| 53 | { 0x00001b88, 0x00020000, 0x00020000}, | ||
| 54 | /* HOST1X_THOST_COMMON_VI_STRMID_2_OFFSET_BASE_0 */ | ||
| 55 | { 0x00001b90, 0x00030000, 0x00030000}, | ||
| 56 | /* HOST1X_THOST_COMMON_VI_STRMID_3_OFFSET_BASE_0 */ | ||
| 57 | { 0x00001b98, 0x00040000, 0x00040000}, | ||
| 58 | /* HOST1X_THOST_COMMON_VI_STRMID_4_OFFSET_BASE_0 */ | ||
| 59 | { 0x00001ba0, 0x00050000, 0x00050000}, | ||
| 60 | /* HOST1X_THOST_COMMON_VI_STRMID_5_OFFSET_BASE_0 */ | ||
| 61 | { 0x00001ba8, 0x00060000, 0x00060000}, | ||
| 62 | /* HOST1X_THOST_COMMON_VI_STRMID_6_OFFSET_BASE_0 */ | ||
| 63 | { 0x00001bb0, 0x00070000, 0x00070000}, | ||
| 64 | /* HOST1X_THOST_COMMON_VI_STRMID_7_OFFSET_BASE_0 */ | ||
| 65 | { 0x00001bb8, 0x00080000, 0x00080000}, | ||
| 66 | /* HOST1X_THOST_COMMON_VI_STRMID_8_OFFSET_BASE_0 */ | ||
| 67 | { 0x00001bc0, 0x00090000, 0x00090000}, | ||
| 68 | /* HOST1X_THOST_COMMON_VI_STRMID_9_OFFSET_BASE_0 */ | ||
| 69 | { 0x00001bc8, 0x000a0000, 0x000a0000}, | ||
| 70 | /* HOST1X_THOST_COMMON_VI_STRMID_10_OFFSET_BASE_0 */ | ||
| 71 | { 0x00001bd0, 0x000b0000, 0x000b0000}, | ||
| 72 | /* HOST1X_THOST_COMMON_VI_STRMID_11_OFFSET_BASE_0 */ | ||
| 73 | { 0x00001bd8, 0x000c0000, 0x000c0000}, | ||
| 74 | {}, | ||
| 75 | }; | ||
| 76 | |||
| 77 | static int load_streamid_regs(struct host1x *host) | ||
| 78 | { | ||
| 79 | struct host1x_streamid_mapping *map_regs = t18x_host1x_streamid_mapping; | ||
| 80 | |||
| 81 | while (map_regs->host1x_offset) { | ||
| 82 | host1x_writel(host, map_regs->client_offset, | ||
| 83 | map_regs->host1x_offset); | ||
| 84 | host1x_writel(host, map_regs->client_limit, | ||
| 85 | map_regs->host1x_offset + sizeof(u32)); | ||
| 86 | |||
| 87 | map_regs++; | ||
| 88 | } | ||
| 89 | |||
| 90 | return 0; | ||
| 91 | } | ||
| 92 | |||
| 93 | static const struct host1x_dev_ops host1x_dev_t186_ops = { | ||
| 94 | .load_regs = load_streamid_regs, | ||
| 95 | }; | ||
diff --git a/drivers/gpu/host1x/hw/syncpt_hw_t186.c b/drivers/gpu/host1x/hw/syncpt_hw_t186.c new file mode 100644 index 000000000..9b196854a --- /dev/null +++ b/drivers/gpu/host1x/hw/syncpt_hw_t186.c | |||
| @@ -0,0 +1,126 @@ | |||
| 1 | /* | ||
| 2 | * Tegra host1x Syncpoints | ||
| 3 | * | ||
| 4 | * Copyright (c) 2016, NVIDIA Corporation. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms and conditions of the GNU General Public License, | ||
| 8 | * version 2, as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 13 | * more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/io.h> | ||
| 20 | |||
| 21 | #include "dev.h" | ||
| 22 | #include "syncpt.h" | ||
| 23 | |||
| 24 | /* | ||
| 25 | * Write the current syncpoint value back to hw. | ||
| 26 | */ | ||
| 27 | static void syncpt_restore(struct host1x_syncpt *sp) | ||
| 28 | { | ||
| 29 | struct host1x *host = sp->host; | ||
| 30 | int min = host1x_syncpt_read_min(sp); | ||
| 31 | host1x_sync_writel(host, min, HOST1X_SYNC_SYNCPT(sp->id)); | ||
| 32 | } | ||
| 33 | |||
| 34 | /* | ||
| 35 | * Write the current waitbase value back to hw. | ||
| 36 | */ | ||
| 37 | static void syncpt_restore_wait_base(struct host1x_syncpt *sp) | ||
| 38 | { | ||
| 39 | struct host1x *host = sp->host; | ||
| 40 | host1x_sync_writel(host, sp->base_val, | ||
| 41 | HOST1X_SYNC_SYNCPT_BASE(sp->id)); | ||
| 42 | } | ||
| 43 | |||
| 44 | /* | ||
| 45 | * Read waitbase value from hw. | ||
| 46 | */ | ||
| 47 | static void syncpt_read_wait_base(struct host1x_syncpt *sp) | ||
| 48 | { | ||
| 49 | struct host1x *host = sp->host; | ||
| 50 | sp->base_val = | ||
| 51 | host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_BASE(sp->id)); | ||
| 52 | } | ||
| 53 | |||
| 54 | /* | ||
| 55 | * Updates the last value read from hardware. | ||
| 56 | */ | ||
| 57 | static u32 syncpt_load(struct host1x_syncpt *sp) | ||
| 58 | { | ||
| 59 | struct host1x *host = sp->host; | ||
| 60 | u32 old, live; | ||
| 61 | |||
| 62 | /* Loop in case there's a race writing to min_val */ | ||
| 63 | do { | ||
| 64 | old = host1x_syncpt_read_min(sp); | ||
| 65 | live = host1x_sync_readl(host, HOST1X_SYNC_SYNCPT(sp->id)); | ||
| 66 | } while ((u32)atomic_cmpxchg(&sp->min_val, old, live) != old); | ||
| 67 | |||
| 68 | if (!host1x_syncpt_check_max(sp, live)) | ||
| 69 | dev_err(host->dev, "%s failed: id=%u, min=%d, max=%d\n", | ||
| 70 | __func__, sp->id, host1x_syncpt_read_min(sp), | ||
| 71 | host1x_syncpt_read_max(sp)); | ||
| 72 | |||
| 73 | return live; | ||
| 74 | } | ||
| 75 | |||
| 76 | /* | ||
| 77 | * Write a cpu syncpoint increment to the hardware, without touching | ||
| 78 | * the cache. | ||
| 79 | */ | ||
| 80 | static int syncpt_cpu_incr(struct host1x_syncpt *sp) | ||
| 81 | { | ||
| 82 | struct host1x *host = sp->host; | ||
| 83 | u32 reg_offset = sp->id / 32; | ||
| 84 | |||
| 85 | if (!host1x_syncpt_client_managed(sp) && | ||
| 86 | host1x_syncpt_idle(sp)) | ||
| 87 | return -EINVAL; | ||
| 88 | host1x_sync_writel(host, BIT_MASK(sp->id), | ||
| 89 | HOST1X_SYNC_SYNCPT_CPU_INCR(reg_offset)); | ||
| 90 | wmb(); | ||
| 91 | |||
| 92 | return 0; | ||
| 93 | } | ||
| 94 | |||
| 95 | /* remove a wait pointed to by patch_addr */ | ||
| 96 | static int syncpt_patch_wait(struct host1x_syncpt *sp, void *patch_addr) | ||
| 97 | { | ||
| 98 | u32 override = host1x_class_host_wait_syncpt( | ||
| 99 | HOST1X_SYNCPT_RESERVED, 0); | ||
| 100 | |||
| 101 | *((u32 *)patch_addr) = override; | ||
| 102 | return 0; | ||
| 103 | } | ||
| 104 | |||
| 105 | static void syncpt_get_mutex_owner(struct host1x_syncpt *sp, | ||
| 106 | unsigned int mutex_id, bool *cpu, bool *ch, | ||
| 107 | unsigned int *chid) | ||
| 108 | { | ||
| 109 | struct host1x *host = sp->host; | ||
| 110 | u32 owner; | ||
| 111 | |||
| 112 | owner = host1x_sync_readl(host, host1x_sync_common_mlock_r(mutex_id)); | ||
| 113 | *chid = HOST1X_SYNC_COMMON_MLOCK_CH_V(owner); | ||
| 114 | *ch = HOST1X_SYNC_COMMON_MLOCK_LOCKED_V(owner); | ||
| 115 | *cpu = false; | ||
| 116 | } | ||
| 117 | |||
| 118 | static const struct host1x_syncpt_ops host1x_syncpt_t186_ops = { | ||
| 119 | .restore = syncpt_restore, | ||
| 120 | .restore_wait_base = syncpt_restore_wait_base, | ||
| 121 | .load_wait_base = syncpt_read_wait_base, | ||
| 122 | .load = syncpt_load, | ||
| 123 | .cpu_incr = syncpt_cpu_incr, | ||
| 124 | .patch_wait = syncpt_patch_wait, | ||
| 125 | .get_mutex_owner = syncpt_get_mutex_owner, | ||
| 126 | }; | ||
