xtensa.c 5.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * Copyright 2013 Ilia Mirkin
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
#include <engine/xtensa.h>

24 25
#include <core/engctx.h>

26
u32
27
_nvkm_xtensa_rd32(struct nvkm_object *object, u64 addr)
28
{
29
	struct nvkm_xtensa *xtensa = (void *)object;
30
	return nvkm_rd32(xtensa->engine.subdev.device, xtensa->addr + addr);
31 32 33
}

void
34
_nvkm_xtensa_wr32(struct nvkm_object *object, u64 addr, u32 data)
35
{
36
	struct nvkm_xtensa *xtensa = (void *)object;
37
	nvkm_wr32(xtensa->engine.subdev.device, xtensa->addr + addr, data);
38 39 40
}

int
41 42 43
_nvkm_xtensa_engctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
			 struct nvkm_oclass *oclass, void *data, u32 size,
			 struct nvkm_object **pobject)
44
{
45
	struct nvkm_engctx *engctx;
46 47
	int ret;

48 49
	ret = nvkm_engctx_create(parent, engine, oclass, NULL, 0x10000, 0x1000,
				 NVOBJ_FLAG_ZERO_ALLOC, &engctx);
50 51 52 53 54
	*pobject = nv_object(engctx);
	return ret;
}

void
55
_nvkm_xtensa_intr(struct nvkm_subdev *subdev)
56
{
57
	struct nvkm_xtensa *xtensa = (void *)subdev;
58
	struct nvkm_device *device = xtensa->engine.subdev.device;
59 60 61 62 63 64
	u32 unk104 = nv_ro32(xtensa, 0xd04);
	u32 intr = nv_ro32(xtensa, 0xc20);
	u32 chan = nv_ro32(xtensa, 0xc28);
	u32 unk10c = nv_ro32(xtensa, 0xd0c);

	if (intr & 0x10)
65
		nvkm_warn(subdev, "Watchdog interrupt, engine hung.\n");
66 67 68
	nv_wo32(xtensa, 0xc20, intr);
	intr = nv_ro32(xtensa, 0xc20);
	if (unk104 == 0x10001 && unk10c == 0x200 && chan && !intr) {
69
		nvkm_debug(subdev, "Enabling FIFO_CTRL\n");
70
		nvkm_mask(device, xtensa->addr + 0xd94, 0, xtensa->fifo_val);
71 72 73 74
	}
}

int
75 76 77 78
nvkm_xtensa_create_(struct nvkm_object *parent, struct nvkm_object *engine,
		    struct nvkm_oclass *oclass, u32 addr, bool enable,
		    const char *iname, const char *fname,
		    int length, void **pobject)
79
{
80
	struct nvkm_xtensa *xtensa;
81 82
	int ret;

83 84
	ret = nvkm_engine_create_(parent, engine, oclass, enable, iname,
				  fname, length, pobject);
85 86 87 88
	xtensa = *pobject;
	if (ret)
		return ret;

89
	nv_subdev(xtensa)->intr = _nvkm_xtensa_intr;
90 91 92 93 94
	xtensa->addr = addr;
	return 0;
}

int
95
_nvkm_xtensa_init(struct nvkm_object *object)
96
{
97
	struct nvkm_xtensa *xtensa = (void *)object;
98 99
	struct nvkm_subdev *subdev = &xtensa->engine.subdev;
	struct nvkm_device *device = subdev->device;
100 101 102 103 104
	const struct firmware *fw;
	char name[32];
	int i, ret;
	u32 tmp;

105
	ret = nvkm_engine_init(&xtensa->engine);
106 107 108 109 110 111 112
	if (ret)
		return ret;

	if (!xtensa->gpu_fw) {
		snprintf(name, sizeof(name), "nouveau/nv84_xuc%03x",
			 xtensa->addr >> 12);

A
Alexandre Courbot 已提交
113
		ret = request_firmware(&fw, name, nv_device_base(device));
114
		if (ret) {
115
			nvkm_warn(subdev, "unable to load firmware %s\n", name);
116 117 118
			return ret;
		}

119
		if (fw->size > 0x40000) {
120
			nvkm_warn(subdev, "firmware %s too large\n", name);
121 122 123 124
			release_firmware(fw);
			return -EINVAL;
		}

125 126
		ret = nvkm_gpuobj_new(object, NULL, 0x40000, 0x1000, 0,
				      &xtensa->gpu_fw);
127 128 129 130 131
		if (ret) {
			release_firmware(fw);
			return ret;
		}

132 133
		nvkm_debug(subdev, "Loading firmware to address: %010llx\n",
			   xtensa->gpu_fw->addr);
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150

		for (i = 0; i < fw->size / 4; i++)
			nv_wo32(xtensa->gpu_fw, i * 4, *((u32 *)fw->data + i));
		release_firmware(fw);
	}

	nv_wo32(xtensa, 0xd10, 0x1fffffff); /* ?? */
	nv_wo32(xtensa, 0xd08, 0x0fffffff); /* ?? */

	nv_wo32(xtensa, 0xd28, xtensa->unkd28); /* ?? */
	nv_wo32(xtensa, 0xc20, 0x3f); /* INTR */
	nv_wo32(xtensa, 0xd84, 0x3f); /* INTR_EN */

	nv_wo32(xtensa, 0xcc0, xtensa->gpu_fw->addr >> 8); /* XT_REGION_BASE */
	nv_wo32(xtensa, 0xcc4, 0x1c); /* XT_REGION_SETUP */
	nv_wo32(xtensa, 0xcc8, xtensa->gpu_fw->size >> 8); /* XT_REGION_LIMIT */

151
	tmp = nvkm_rd32(device, 0x0);
152 153 154 155 156 157 158 159 160 161
	nv_wo32(xtensa, 0xde0, tmp); /* SCRATCH_H2X */

	nv_wo32(xtensa, 0xce8, 0xf); /* XT_REGION_SETUP */

	nv_wo32(xtensa, 0xc20, 0x3f); /* INTR */
	nv_wo32(xtensa, 0xd84, 0x3f); /* INTR_EN */
	return 0;
}

int
162
_nvkm_xtensa_fini(struct nvkm_object *object, bool suspend)
163
{
164
	struct nvkm_xtensa *xtensa = (void *)object;
165 166 167 168 169

	nv_wo32(xtensa, 0xd84, 0); /* INTR_EN */
	nv_wo32(xtensa, 0xd94, 0); /* FIFO_CTRL */

	if (!suspend)
170
		nvkm_gpuobj_ref(NULL, &xtensa->gpu_fw);
171

172
	return nvkm_engine_fini(&xtensa->engine, suspend);
173
}