1d390b480SBen Skeggs /*
2d390b480SBen Skeggs  * Copyright 2012 Red Hat Inc.
3d390b480SBen Skeggs  *
4d390b480SBen Skeggs  * Permission is hereby granted, free of charge, to any person obtaining a
5d390b480SBen Skeggs  * copy of this software and associated documentation files (the "Software"),
6d390b480SBen Skeggs  * to deal in the Software without restriction, including without limitation
7d390b480SBen Skeggs  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8d390b480SBen Skeggs  * and/or sell copies of the Software, and to permit persons to whom the
9d390b480SBen Skeggs  * Software is furnished to do so, subject to the following conditions:
10d390b480SBen Skeggs  *
11d390b480SBen Skeggs  * The above copyright notice and this permission notice shall be included in
12d390b480SBen Skeggs  * all copies or substantial portions of the Software.
13d390b480SBen Skeggs  *
14d390b480SBen Skeggs  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15d390b480SBen Skeggs  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16d390b480SBen Skeggs  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17d390b480SBen Skeggs  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18d390b480SBen Skeggs  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19d390b480SBen Skeggs  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20d390b480SBen Skeggs  * OTHER DEALINGS IN THE SOFTWARE.
21d390b480SBen Skeggs  *
22d390b480SBen Skeggs  * Authors: Ben Skeggs
23d390b480SBen Skeggs  */
24c39f472eSBen Skeggs #include <subdev/bios.h>
25c39f472eSBen Skeggs #include <subdev/bios/bit.h>
26d390b480SBen Skeggs #include <subdev/bios/bmp.h>
27c39f472eSBen Skeggs #include <subdev/bios/conn.h>
28c39f472eSBen Skeggs #include <subdev/bios/dcb.h>
29c39f472eSBen Skeggs #include <subdev/bios/dp.h>
30c39f472eSBen Skeggs #include <subdev/bios/gpio.h>
31c39f472eSBen Skeggs #include <subdev/bios/init.h>
32c39f472eSBen Skeggs #include <subdev/bios/ramcfg.h>
33b9ec1424SBen Skeggs 
34c39f472eSBen Skeggs #include <subdev/devinit.h>
35d390b480SBen Skeggs #include <subdev/gpio.h>
36c39f472eSBen Skeggs #include <subdev/i2c.h>
37c39f472eSBen Skeggs #include <subdev/vga.h>
38c39f472eSBen Skeggs 
3973cef6ceSJérémy Lefaure #include <linux/kernel.h>
4073cef6ceSJérémy Lefaure 
41c39f472eSBen Skeggs #define bioslog(lvl, fmt, args...) do {                                        \
42ca9c2d5bSBen Skeggs 	nvkm_printk(init->subdev, lvl, info, "0x%08x[%c]: "fmt,                \
4360b29d20SBen Skeggs 		    init->offset, init_exec(init) ?                            \
4460b29d20SBen Skeggs 		    '0' + (init->nested - 1) : ' ', ##args);                   \
45c39f472eSBen Skeggs } while(0)
46c39f472eSBen Skeggs #define cont(fmt, args...) do {                                                \
4760b29d20SBen Skeggs 	if (init->subdev->debug >= NV_DBG_TRACE)                               \
48c39f472eSBen Skeggs 		printk(fmt, ##args);                                           \
49c39f472eSBen Skeggs } while(0)
50c39f472eSBen Skeggs #define trace(fmt, args...) bioslog(TRACE, fmt, ##args)
51c39f472eSBen Skeggs #define warn(fmt, args...) bioslog(WARN, fmt, ##args)
52c39f472eSBen Skeggs #define error(fmt, args...) bioslog(ERROR, fmt, ##args)
53c39f472eSBen Skeggs 
54c39f472eSBen Skeggs /******************************************************************************
55c39f472eSBen Skeggs  * init parser control flow helpers
56c39f472eSBen Skeggs  *****************************************************************************/
57c39f472eSBen Skeggs 
58c39f472eSBen Skeggs static inline bool
init_exec(struct nvbios_init * init)59c39f472eSBen Skeggs init_exec(struct nvbios_init *init)
60c39f472eSBen Skeggs {
61c39f472eSBen Skeggs 	return (init->execute == 1) || ((init->execute & 5) == 5);
62c39f472eSBen Skeggs }
63c39f472eSBen Skeggs 
64c39f472eSBen Skeggs static inline void
init_exec_set(struct nvbios_init * init,bool exec)65c39f472eSBen Skeggs init_exec_set(struct nvbios_init *init, bool exec)
66c39f472eSBen Skeggs {
67c39f472eSBen Skeggs 	if (exec) init->execute &= 0xfd;
68c39f472eSBen Skeggs 	else      init->execute |= 0x02;
69c39f472eSBen Skeggs }
70c39f472eSBen Skeggs 
71c39f472eSBen Skeggs static inline void
init_exec_inv(struct nvbios_init * init)72c39f472eSBen Skeggs init_exec_inv(struct nvbios_init *init)
73c39f472eSBen Skeggs {
74c39f472eSBen Skeggs 	init->execute ^= 0x02;
75c39f472eSBen Skeggs }
76c39f472eSBen Skeggs 
77c39f472eSBen Skeggs static inline void
init_exec_force(struct nvbios_init * init,bool exec)78c39f472eSBen Skeggs init_exec_force(struct nvbios_init *init, bool exec)
79c39f472eSBen Skeggs {
80c39f472eSBen Skeggs 	if (exec) init->execute |= 0x04;
81c39f472eSBen Skeggs 	else      init->execute &= 0xfb;
82c39f472eSBen Skeggs }
83c39f472eSBen Skeggs 
84c39f472eSBen Skeggs /******************************************************************************
85c39f472eSBen Skeggs  * init parser wrappers for normal register/i2c/whatever accessors
86c39f472eSBen Skeggs  *****************************************************************************/
87c39f472eSBen Skeggs 
88c39f472eSBen Skeggs static inline int
init_or(struct nvbios_init * init)89c39f472eSBen Skeggs init_or(struct nvbios_init *init)
90c39f472eSBen Skeggs {
91c39f472eSBen Skeggs 	if (init_exec(init)) {
92b88afa43SBen Skeggs 		if (init->or >= 0)
93b88afa43SBen Skeggs 			return init->or;
94c39f472eSBen Skeggs 		error("script needs OR!!\n");
95c39f472eSBen Skeggs 	}
96c39f472eSBen Skeggs 	return 0;
97c39f472eSBen Skeggs }
98c39f472eSBen Skeggs 
99c39f472eSBen Skeggs static inline int
init_link(struct nvbios_init * init)100c39f472eSBen Skeggs init_link(struct nvbios_init *init)
101c39f472eSBen Skeggs {
102c39f472eSBen Skeggs 	if (init_exec(init)) {
103b88afa43SBen Skeggs 		if (init->link)
104b88afa43SBen Skeggs 			return init->link == 2;
105c39f472eSBen Skeggs 		error("script needs OR link\n");
106c39f472eSBen Skeggs 	}
107c39f472eSBen Skeggs 	return 0;
108c39f472eSBen Skeggs }
109c39f472eSBen Skeggs 
110c39f472eSBen Skeggs static inline int
init_head(struct nvbios_init * init)1112195a22fSBen Skeggs init_head(struct nvbios_init *init)
112c39f472eSBen Skeggs {
113c39f472eSBen Skeggs 	if (init_exec(init)) {
1142195a22fSBen Skeggs 		if (init->head >= 0)
1152195a22fSBen Skeggs 			return init->head;
1162195a22fSBen Skeggs 		error("script needs head\n");
117c39f472eSBen Skeggs 	}
118c39f472eSBen Skeggs 	return 0;
119c39f472eSBen Skeggs }
120c39f472eSBen Skeggs 
121c39f472eSBen Skeggs static u8
init_conn(struct nvbios_init * init)122c39f472eSBen Skeggs init_conn(struct nvbios_init *init)
123c39f472eSBen Skeggs {
1245b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
125c39f472eSBen Skeggs 	struct nvbios_connE connE;
126c39f472eSBen Skeggs 	u8  ver, hdr;
127c39f472eSBen Skeggs 	u32 conn;
128c39f472eSBen Skeggs 
129c39f472eSBen Skeggs 	if (init_exec(init)) {
130c39f472eSBen Skeggs 		if (init->outp) {
131c39f472eSBen Skeggs 			conn = init->outp->connector;
132c39f472eSBen Skeggs 			conn = nvbios_connEp(bios, conn, &ver, &hdr, &connE);
133c39f472eSBen Skeggs 			if (conn)
134c39f472eSBen Skeggs 				return connE.type;
135c39f472eSBen Skeggs 		}
136c39f472eSBen Skeggs 
137c39f472eSBen Skeggs 		error("script needs connector type\n");
138c39f472eSBen Skeggs 	}
139c39f472eSBen Skeggs 
140c39f472eSBen Skeggs 	return 0xff;
141c39f472eSBen Skeggs }
142c39f472eSBen Skeggs 
143c39f472eSBen Skeggs static inline u32
init_nvreg(struct nvbios_init * init,u32 reg)144c39f472eSBen Skeggs init_nvreg(struct nvbios_init *init, u32 reg)
145c39f472eSBen Skeggs {
1465b0e787aSBen Skeggs 	struct nvkm_devinit *devinit = init->subdev->device->devinit;
147c39f472eSBen Skeggs 
148c39f472eSBen Skeggs 	/* C51 (at least) sometimes has the lower bits set which the VBIOS
149c39f472eSBen Skeggs 	 * interprets to mean that access needs to go through certain IO
150c39f472eSBen Skeggs 	 * ports instead.  The NVIDIA binary driver has been seen to access
151c39f472eSBen Skeggs 	 * these through the NV register address, so lets assume we can
152c39f472eSBen Skeggs 	 * do the same
153c39f472eSBen Skeggs 	 */
154c39f472eSBen Skeggs 	reg &= ~0x00000003;
155c39f472eSBen Skeggs 
156c39f472eSBen Skeggs 	/* GF8+ display scripts need register addresses mangled a bit to
157c39f472eSBen Skeggs 	 * select a specific CRTC/OR
158c39f472eSBen Skeggs 	 */
1595b0e787aSBen Skeggs 	if (init->subdev->device->card_type >= NV_50) {
160c39f472eSBen Skeggs 		if (reg & 0x80000000) {
1612195a22fSBen Skeggs 			reg += init_head(init) * 0x800;
162c39f472eSBen Skeggs 			reg &= ~0x80000000;
163c39f472eSBen Skeggs 		}
164c39f472eSBen Skeggs 
165c39f472eSBen Skeggs 		if (reg & 0x40000000) {
166c39f472eSBen Skeggs 			reg += init_or(init) * 0x800;
167c39f472eSBen Skeggs 			reg &= ~0x40000000;
168c39f472eSBen Skeggs 			if (reg & 0x20000000) {
169c39f472eSBen Skeggs 				reg += init_link(init) * 0x80;
170c39f472eSBen Skeggs 				reg &= ~0x20000000;
171c39f472eSBen Skeggs 			}
172c39f472eSBen Skeggs 		}
173c39f472eSBen Skeggs 	}
174c39f472eSBen Skeggs 
175c39f472eSBen Skeggs 	if (reg & ~0x00fffffc)
176c39f472eSBen Skeggs 		warn("unknown bits in register 0x%08x\n", reg);
177c39f472eSBen Skeggs 
178151abd44SBen Skeggs 	return nvkm_devinit_mmio(devinit, reg);
179c39f472eSBen Skeggs }
180c39f472eSBen Skeggs 
181c39f472eSBen Skeggs static u32
init_rd32(struct nvbios_init * init,u32 reg)182c39f472eSBen Skeggs init_rd32(struct nvbios_init *init, u32 reg)
183c39f472eSBen Skeggs {
1845b0e787aSBen Skeggs 	struct nvkm_device *device = init->subdev->device;
185c39f472eSBen Skeggs 	reg = init_nvreg(init, reg);
186c39f472eSBen Skeggs 	if (reg != ~0 && init_exec(init))
187d8f266a3SBen Skeggs 		return nvkm_rd32(device, reg);
188c39f472eSBen Skeggs 	return 0x00000000;
189c39f472eSBen Skeggs }
190c39f472eSBen Skeggs 
191c39f472eSBen Skeggs static void
init_wr32(struct nvbios_init * init,u32 reg,u32 val)192c39f472eSBen Skeggs init_wr32(struct nvbios_init *init, u32 reg, u32 val)
193c39f472eSBen Skeggs {
1945b0e787aSBen Skeggs 	struct nvkm_device *device = init->subdev->device;
195c39f472eSBen Skeggs 	reg = init_nvreg(init, reg);
196c39f472eSBen Skeggs 	if (reg != ~0 && init_exec(init))
197d8f266a3SBen Skeggs 		nvkm_wr32(device, reg, val);
198c39f472eSBen Skeggs }
199c39f472eSBen Skeggs 
200c39f472eSBen Skeggs static u32
init_mask(struct nvbios_init * init,u32 reg,u32 mask,u32 val)201c39f472eSBen Skeggs init_mask(struct nvbios_init *init, u32 reg, u32 mask, u32 val)
202c39f472eSBen Skeggs {
2035b0e787aSBen Skeggs 	struct nvkm_device *device = init->subdev->device;
204c39f472eSBen Skeggs 	reg = init_nvreg(init, reg);
205c39f472eSBen Skeggs 	if (reg != ~0 && init_exec(init)) {
206d8f266a3SBen Skeggs 		u32 tmp = nvkm_rd32(device, reg);
207d8f266a3SBen Skeggs 		nvkm_wr32(device, reg, (tmp & ~mask) | val);
208c39f472eSBen Skeggs 		return tmp;
209c39f472eSBen Skeggs 	}
210c39f472eSBen Skeggs 	return 0x00000000;
211c39f472eSBen Skeggs }
212c39f472eSBen Skeggs 
213c39f472eSBen Skeggs static u8
init_rdport(struct nvbios_init * init,u16 port)214c39f472eSBen Skeggs init_rdport(struct nvbios_init *init, u16 port)
215c39f472eSBen Skeggs {
216c39f472eSBen Skeggs 	if (init_exec(init))
2172195a22fSBen Skeggs 		return nvkm_rdport(init->subdev->device, init->head, port);
218c39f472eSBen Skeggs 	return 0x00;
219c39f472eSBen Skeggs }
220c39f472eSBen Skeggs 
221c39f472eSBen Skeggs static void
init_wrport(struct nvbios_init * init,u16 port,u8 value)222c39f472eSBen Skeggs init_wrport(struct nvbios_init *init, u16 port, u8 value)
223c39f472eSBen Skeggs {
224c39f472eSBen Skeggs 	if (init_exec(init))
2252195a22fSBen Skeggs 		nvkm_wrport(init->subdev->device, init->head, port, value);
226c39f472eSBen Skeggs }
227c39f472eSBen Skeggs 
228c39f472eSBen Skeggs static u8
init_rdvgai(struct nvbios_init * init,u16 port,u8 index)229c39f472eSBen Skeggs init_rdvgai(struct nvbios_init *init, u16 port, u8 index)
230c39f472eSBen Skeggs {
231d390b480SBen Skeggs 	struct nvkm_subdev *subdev = init->subdev;
232c39f472eSBen Skeggs 	if (init_exec(init)) {
2332195a22fSBen Skeggs 		int head = init->head < 0 ? 0 : init->head;
234a8dae9feSBen Skeggs 		return nvkm_rdvgai(subdev->device, head, port, index);
235c39f472eSBen Skeggs 	}
236c39f472eSBen Skeggs 	return 0x00;
237c39f472eSBen Skeggs }
238c39f472eSBen Skeggs 
239c39f472eSBen Skeggs static void
init_wrvgai(struct nvbios_init * init,u16 port,u8 index,u8 value)240c39f472eSBen Skeggs init_wrvgai(struct nvbios_init *init, u16 port, u8 index, u8 value)
241c39f472eSBen Skeggs {
242a8dae9feSBen Skeggs 	struct nvkm_device *device = init->subdev->device;
243a8dae9feSBen Skeggs 
244c39f472eSBen Skeggs 	/* force head 0 for updates to cr44, it only exists on first head */
245a8dae9feSBen Skeggs 	if (device->card_type < NV_50) {
246c39f472eSBen Skeggs 		if (port == 0x03d4 && index == 0x44)
2472195a22fSBen Skeggs 			init->head = 0;
248c39f472eSBen Skeggs 	}
249c39f472eSBen Skeggs 
250c39f472eSBen Skeggs 	if (init_exec(init)) {
2512195a22fSBen Skeggs 		int head = init->head < 0 ? 0 : init->head;
252a8dae9feSBen Skeggs 		nvkm_wrvgai(device, head, port, index, value);
253c39f472eSBen Skeggs 	}
254c39f472eSBen Skeggs 
255c39f472eSBen Skeggs 	/* select head 1 if cr44 write selected it */
256a8dae9feSBen Skeggs 	if (device->card_type < NV_50) {
257c39f472eSBen Skeggs 		if (port == 0x03d4 && index == 0x44 && value == 3)
2582195a22fSBen Skeggs 			init->head = 1;
259c39f472eSBen Skeggs 	}
260c39f472eSBen Skeggs }
261c39f472eSBen Skeggs 
2622aa5eac5SBen Skeggs static struct i2c_adapter *
init_i2c(struct nvbios_init * init,int index)263c39f472eSBen Skeggs init_i2c(struct nvbios_init *init, int index)
264c39f472eSBen Skeggs {
2655b0e787aSBen Skeggs 	struct nvkm_i2c *i2c = init->subdev->device->i2c;
2662aa5eac5SBen Skeggs 	struct nvkm_i2c_bus *bus;
267c39f472eSBen Skeggs 
268c39f472eSBen Skeggs 	if (index == 0xff) {
2692aa5eac5SBen Skeggs 		index = NVKM_I2C_BUS_PRI;
270c39f472eSBen Skeggs 		if (init->outp && init->outp->i2c_upper_default)
2712aa5eac5SBen Skeggs 			index = NVKM_I2C_BUS_SEC;
2722239b76bSBen Skeggs 	} else
2732239b76bSBen Skeggs 	if (index == 0x80) {
2742239b76bSBen Skeggs 		index = NVKM_I2C_BUS_PRI;
2752239b76bSBen Skeggs 	} else
2762239b76bSBen Skeggs 	if (index == 0x81) {
2772239b76bSBen Skeggs 		index = NVKM_I2C_BUS_SEC;
278c39f472eSBen Skeggs 	}
279c39f472eSBen Skeggs 
2802aa5eac5SBen Skeggs 	bus = nvkm_i2c_bus_find(i2c, index);
2812aa5eac5SBen Skeggs 	return bus ? &bus->i2c : NULL;
282c39f472eSBen Skeggs }
283c39f472eSBen Skeggs 
284c39f472eSBen Skeggs static int
init_rdi2cr(struct nvbios_init * init,u8 index,u8 addr,u8 reg)285c39f472eSBen Skeggs init_rdi2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg)
286c39f472eSBen Skeggs {
2872aa5eac5SBen Skeggs 	struct i2c_adapter *adap = init_i2c(init, index);
2882aa5eac5SBen Skeggs 	if (adap && init_exec(init))
2892aa5eac5SBen Skeggs 		return nvkm_rdi2cr(adap, addr, reg);
290c39f472eSBen Skeggs 	return -ENODEV;
291c39f472eSBen Skeggs }
292c39f472eSBen Skeggs 
293c39f472eSBen Skeggs static int
init_wri2cr(struct nvbios_init * init,u8 index,u8 addr,u8 reg,u8 val)294c39f472eSBen Skeggs init_wri2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg, u8 val)
295c39f472eSBen Skeggs {
2962aa5eac5SBen Skeggs 	struct i2c_adapter *adap = init_i2c(init, index);
2972aa5eac5SBen Skeggs 	if (adap && init_exec(init))
2982aa5eac5SBen Skeggs 		return nvkm_wri2cr(adap, addr, reg, val);
299c39f472eSBen Skeggs 	return -ENODEV;
300c39f472eSBen Skeggs }
301c39f472eSBen Skeggs 
3022aa5eac5SBen Skeggs static struct nvkm_i2c_aux *
init_aux(struct nvbios_init * init)3032aa5eac5SBen Skeggs init_aux(struct nvbios_init *init)
3042aa5eac5SBen Skeggs {
3055b0e787aSBen Skeggs 	struct nvkm_i2c *i2c = init->subdev->device->i2c;
3062aa5eac5SBen Skeggs 	if (!init->outp) {
3072aa5eac5SBen Skeggs 		if (init_exec(init))
3082aa5eac5SBen Skeggs 			error("script needs output for aux\n");
3092aa5eac5SBen Skeggs 		return NULL;
3102aa5eac5SBen Skeggs 	}
3112aa5eac5SBen Skeggs 	return nvkm_i2c_aux_find(i2c, init->outp->i2c_index);
3122aa5eac5SBen Skeggs }
3132aa5eac5SBen Skeggs 
314c39f472eSBen Skeggs static u8
init_rdauxr(struct nvbios_init * init,u32 addr)315c39f472eSBen Skeggs init_rdauxr(struct nvbios_init *init, u32 addr)
316c39f472eSBen Skeggs {
3172aa5eac5SBen Skeggs 	struct nvkm_i2c_aux *aux = init_aux(init);
318c39f472eSBen Skeggs 	u8 data;
319c39f472eSBen Skeggs 
3202aa5eac5SBen Skeggs 	if (aux && init_exec(init)) {
3212aa5eac5SBen Skeggs 		int ret = nvkm_rdaux(aux, addr, &data, 1);
322c39f472eSBen Skeggs 		if (ret == 0)
323c39f472eSBen Skeggs 			return data;
324c39f472eSBen Skeggs 		trace("auxch read failed with %d\n", ret);
325c39f472eSBen Skeggs 	}
326c39f472eSBen Skeggs 
327c39f472eSBen Skeggs 	return 0x00;
328c39f472eSBen Skeggs }
329c39f472eSBen Skeggs 
330c39f472eSBen Skeggs static int
init_wrauxr(struct nvbios_init * init,u32 addr,u8 data)331c39f472eSBen Skeggs init_wrauxr(struct nvbios_init *init, u32 addr, u8 data)
332c39f472eSBen Skeggs {
3332aa5eac5SBen Skeggs 	struct nvkm_i2c_aux *aux = init_aux(init);
3342aa5eac5SBen Skeggs 	if (aux && init_exec(init)) {
3352aa5eac5SBen Skeggs 		int ret = nvkm_wraux(aux, addr, &data, 1);
336c39f472eSBen Skeggs 		if (ret)
337c39f472eSBen Skeggs 			trace("auxch write failed with %d\n", ret);
338c39f472eSBen Skeggs 		return ret;
339c39f472eSBen Skeggs 	}
340c39f472eSBen Skeggs 	return -ENODEV;
341c39f472eSBen Skeggs }
342c39f472eSBen Skeggs 
343c39f472eSBen Skeggs static void
init_prog_pll(struct nvbios_init * init,u32 id,u32 freq)344c39f472eSBen Skeggs init_prog_pll(struct nvbios_init *init, u32 id, u32 freq)
345c39f472eSBen Skeggs {
3465b0e787aSBen Skeggs 	struct nvkm_devinit *devinit = init->subdev->device->devinit;
347151abd44SBen Skeggs 	if (init_exec(init)) {
348151abd44SBen Skeggs 		int ret = nvkm_devinit_pll_set(devinit, id, freq);
349c39f472eSBen Skeggs 		if (ret)
350c39f472eSBen Skeggs 			warn("failed to prog pll 0x%08x to %dkHz\n", id, freq);
351c39f472eSBen Skeggs 	}
352c39f472eSBen Skeggs }
353c39f472eSBen Skeggs 
354c39f472eSBen Skeggs /******************************************************************************
355c39f472eSBen Skeggs  * parsing of bios structures that are required to execute init tables
356c39f472eSBen Skeggs  *****************************************************************************/
357c39f472eSBen Skeggs 
358c39f472eSBen Skeggs static u16
init_table(struct nvkm_bios * bios,u16 * len)359d390b480SBen Skeggs init_table(struct nvkm_bios *bios, u16 *len)
360c39f472eSBen Skeggs {
361c39f472eSBen Skeggs 	struct bit_entry bit_I;
362c39f472eSBen Skeggs 
363c39f472eSBen Skeggs 	if (!bit_entry(bios, 'I', &bit_I)) {
364c39f472eSBen Skeggs 		*len = bit_I.length;
365c39f472eSBen Skeggs 		return bit_I.offset;
366c39f472eSBen Skeggs 	}
367c39f472eSBen Skeggs 
368c39f472eSBen Skeggs 	if (bmp_version(bios) >= 0x0510) {
369c39f472eSBen Skeggs 		*len = 14;
370c39f472eSBen Skeggs 		return bios->bmp_offset + 75;
371c39f472eSBen Skeggs 	}
372c39f472eSBen Skeggs 
373c39f472eSBen Skeggs 	return 0x0000;
374c39f472eSBen Skeggs }
375c39f472eSBen Skeggs 
376c39f472eSBen Skeggs static u16
init_table_(struct nvbios_init * init,u16 offset,const char * name)377c39f472eSBen Skeggs init_table_(struct nvbios_init *init, u16 offset, const char *name)
378c39f472eSBen Skeggs {
3795b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
380c39f472eSBen Skeggs 	u16 len, data = init_table(bios, &len);
381c39f472eSBen Skeggs 	if (data) {
382c39f472eSBen Skeggs 		if (len >= offset + 2) {
3837f5f518fSBen Skeggs 			data = nvbios_rd16(bios, data + offset);
384c39f472eSBen Skeggs 			if (data)
385c39f472eSBen Skeggs 				return data;
386c39f472eSBen Skeggs 
387c39f472eSBen Skeggs 			warn("%s pointer invalid\n", name);
388c39f472eSBen Skeggs 			return 0x0000;
389c39f472eSBen Skeggs 		}
390c39f472eSBen Skeggs 
391c39f472eSBen Skeggs 		warn("init data too short for %s pointer", name);
392c39f472eSBen Skeggs 		return 0x0000;
393c39f472eSBen Skeggs 	}
394c39f472eSBen Skeggs 
395c39f472eSBen Skeggs 	warn("init data not found\n");
396c39f472eSBen Skeggs 	return 0x0000;
397c39f472eSBen Skeggs }
398c39f472eSBen Skeggs 
399c39f472eSBen Skeggs #define init_script_table(b) init_table_((b), 0x00, "script table")
400c39f472eSBen Skeggs #define init_macro_index_table(b) init_table_((b), 0x02, "macro index table")
401c39f472eSBen Skeggs #define init_macro_table(b) init_table_((b), 0x04, "macro table")
402c39f472eSBen Skeggs #define init_condition_table(b) init_table_((b), 0x06, "condition table")
403c39f472eSBen Skeggs #define init_io_condition_table(b) init_table_((b), 0x08, "io condition table")
404*c5dac1f6SBhaskar Chowdhury #define init_io_flag_condition_table(b) init_table_((b), 0x0a, "io flag condition table")
405c39f472eSBen Skeggs #define init_function_table(b) init_table_((b), 0x0c, "function table")
406c39f472eSBen Skeggs #define init_xlat_table(b) init_table_((b), 0x10, "xlat table");
407c39f472eSBen Skeggs 
408c39f472eSBen Skeggs static u16
init_script(struct nvkm_bios * bios,int index)409d390b480SBen Skeggs init_script(struct nvkm_bios *bios, int index)
410c39f472eSBen Skeggs {
4115b0e787aSBen Skeggs 	struct nvbios_init init = { .subdev = &bios->subdev };
412c39f472eSBen Skeggs 	u16 bmp_ver = bmp_version(bios), data;
413c39f472eSBen Skeggs 
414c39f472eSBen Skeggs 	if (bmp_ver && bmp_ver < 0x0510) {
415c39f472eSBen Skeggs 		if (index > 1 || bmp_ver < 0x0100)
416c39f472eSBen Skeggs 			return 0x0000;
417c39f472eSBen Skeggs 
418c39f472eSBen Skeggs 		data = bios->bmp_offset + (bmp_ver < 0x0200 ? 14 : 18);
4197f5f518fSBen Skeggs 		return nvbios_rd16(bios, data + (index * 2));
420c39f472eSBen Skeggs 	}
421c39f472eSBen Skeggs 
422c39f472eSBen Skeggs 	data = init_script_table(&init);
423c39f472eSBen Skeggs 	if (data)
4247f5f518fSBen Skeggs 		return nvbios_rd16(bios, data + (index * 2));
425c39f472eSBen Skeggs 
426c39f472eSBen Skeggs 	return 0x0000;
427c39f472eSBen Skeggs }
428c39f472eSBen Skeggs 
429c39f472eSBen Skeggs static u16
init_unknown_script(struct nvkm_bios * bios)430d390b480SBen Skeggs init_unknown_script(struct nvkm_bios *bios)
431c39f472eSBen Skeggs {
432c39f472eSBen Skeggs 	u16 len, data = init_table(bios, &len);
433c39f472eSBen Skeggs 	if (data && len >= 16)
4347f5f518fSBen Skeggs 		return nvbios_rd16(bios, data + 14);
435c39f472eSBen Skeggs 	return 0x0000;
436c39f472eSBen Skeggs }
437c39f472eSBen Skeggs 
438c39f472eSBen Skeggs static u8
init_ram_restrict_group_count(struct nvbios_init * init)439c39f472eSBen Skeggs init_ram_restrict_group_count(struct nvbios_init *init)
440c39f472eSBen Skeggs {
4415b0e787aSBen Skeggs 	return nvbios_ramcfg_count(init->subdev->device->bios);
442c39f472eSBen Skeggs }
443c39f472eSBen Skeggs 
444c39f472eSBen Skeggs static u8
init_ram_restrict(struct nvbios_init * init)445c39f472eSBen Skeggs init_ram_restrict(struct nvbios_init *init)
446c39f472eSBen Skeggs {
447c39f472eSBen Skeggs 	/* This appears to be the behaviour of the VBIOS parser, and *is*
448c39f472eSBen Skeggs 	 * important to cache the NV_PEXTDEV_BOOT0 on later chipsets to
449c39f472eSBen Skeggs 	 * avoid fucking up the memory controller (somehow) by reading it
450c39f472eSBen Skeggs 	 * on every INIT_RAM_RESTRICT_ZM_GROUP opcode.
451c39f472eSBen Skeggs 	 *
452c39f472eSBen Skeggs 	 * Preserving the non-caching behaviour on earlier chipsets just
453c39f472eSBen Skeggs 	 * in case *not* re-reading the strap causes similar breakage.
454c39f472eSBen Skeggs 	 */
4555b0e787aSBen Skeggs 	if (!init->ramcfg || init->subdev->device->bios->version.major < 0x70)
456c39f472eSBen Skeggs 		init->ramcfg = 0x80000000 | nvbios_ramcfg_index(init->subdev);
457c39f472eSBen Skeggs 	return (init->ramcfg & 0x7fffffff);
458c39f472eSBen Skeggs }
459c39f472eSBen Skeggs 
460c39f472eSBen Skeggs static u8
init_xlat_(struct nvbios_init * init,u8 index,u8 offset)461c39f472eSBen Skeggs init_xlat_(struct nvbios_init *init, u8 index, u8 offset)
462c39f472eSBen Skeggs {
4635b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
464c39f472eSBen Skeggs 	u16 table = init_xlat_table(init);
465c39f472eSBen Skeggs 	if (table) {
4667f5f518fSBen Skeggs 		u16 data = nvbios_rd16(bios, table + (index * 2));
467c39f472eSBen Skeggs 		if (data)
4687f5f518fSBen Skeggs 			return nvbios_rd08(bios, data + offset);
469c39f472eSBen Skeggs 		warn("xlat table pointer %d invalid\n", index);
470c39f472eSBen Skeggs 	}
471c39f472eSBen Skeggs 	return 0x00;
472c39f472eSBen Skeggs }
473c39f472eSBen Skeggs 
474c39f472eSBen Skeggs /******************************************************************************
475c39f472eSBen Skeggs  * utility functions used by various init opcode handlers
476c39f472eSBen Skeggs  *****************************************************************************/
477c39f472eSBen Skeggs 
478c39f472eSBen Skeggs static bool
init_condition_met(struct nvbios_init * init,u8 cond)479c39f472eSBen Skeggs init_condition_met(struct nvbios_init *init, u8 cond)
480c39f472eSBen Skeggs {
4815b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
482c39f472eSBen Skeggs 	u16 table = init_condition_table(init);
483c39f472eSBen Skeggs 	if (table) {
4847f5f518fSBen Skeggs 		u32 reg = nvbios_rd32(bios, table + (cond * 12) + 0);
4857f5f518fSBen Skeggs 		u32 msk = nvbios_rd32(bios, table + (cond * 12) + 4);
4867f5f518fSBen Skeggs 		u32 val = nvbios_rd32(bios, table + (cond * 12) + 8);
487c39f472eSBen Skeggs 		trace("\t[0x%02x] (R[0x%06x] & 0x%08x) == 0x%08x\n",
488c39f472eSBen Skeggs 		      cond, reg, msk, val);
489c39f472eSBen Skeggs 		return (init_rd32(init, reg) & msk) == val;
490c39f472eSBen Skeggs 	}
491c39f472eSBen Skeggs 	return false;
492c39f472eSBen Skeggs }
493c39f472eSBen Skeggs 
494c39f472eSBen Skeggs static bool
init_io_condition_met(struct nvbios_init * init,u8 cond)495c39f472eSBen Skeggs init_io_condition_met(struct nvbios_init *init, u8 cond)
496c39f472eSBen Skeggs {
4975b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
498c39f472eSBen Skeggs 	u16 table = init_io_condition_table(init);
499c39f472eSBen Skeggs 	if (table) {
5007f5f518fSBen Skeggs 		u16 port = nvbios_rd16(bios, table + (cond * 5) + 0);
5017f5f518fSBen Skeggs 		u8 index = nvbios_rd08(bios, table + (cond * 5) + 2);
5027f5f518fSBen Skeggs 		u8  mask = nvbios_rd08(bios, table + (cond * 5) + 3);
5037f5f518fSBen Skeggs 		u8 value = nvbios_rd08(bios, table + (cond * 5) + 4);
504c39f472eSBen Skeggs 		trace("\t[0x%02x] (0x%04x[0x%02x] & 0x%02x) == 0x%02x\n",
505c39f472eSBen Skeggs 		      cond, port, index, mask, value);
506c39f472eSBen Skeggs 		return (init_rdvgai(init, port, index) & mask) == value;
507c39f472eSBen Skeggs 	}
508c39f472eSBen Skeggs 	return false;
509c39f472eSBen Skeggs }
510c39f472eSBen Skeggs 
511c39f472eSBen Skeggs static bool
init_io_flag_condition_met(struct nvbios_init * init,u8 cond)512c39f472eSBen Skeggs init_io_flag_condition_met(struct nvbios_init *init, u8 cond)
513c39f472eSBen Skeggs {
5145b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
515c39f472eSBen Skeggs 	u16 table = init_io_flag_condition_table(init);
516c39f472eSBen Skeggs 	if (table) {
5177f5f518fSBen Skeggs 		u16 port = nvbios_rd16(bios, table + (cond * 9) + 0);
5187f5f518fSBen Skeggs 		u8 index = nvbios_rd08(bios, table + (cond * 9) + 2);
5197f5f518fSBen Skeggs 		u8  mask = nvbios_rd08(bios, table + (cond * 9) + 3);
5207f5f518fSBen Skeggs 		u8 shift = nvbios_rd08(bios, table + (cond * 9) + 4);
5217f5f518fSBen Skeggs 		u16 data = nvbios_rd16(bios, table + (cond * 9) + 5);
5227f5f518fSBen Skeggs 		u8 dmask = nvbios_rd08(bios, table + (cond * 9) + 7);
5237f5f518fSBen Skeggs 		u8 value = nvbios_rd08(bios, table + (cond * 9) + 8);
524c39f472eSBen Skeggs 		u8 ioval = (init_rdvgai(init, port, index) & mask) >> shift;
5257f5f518fSBen Skeggs 		return (nvbios_rd08(bios, data + ioval) & dmask) == value;
526c39f472eSBen Skeggs 	}
527c39f472eSBen Skeggs 	return false;
528c39f472eSBen Skeggs }
529c39f472eSBen Skeggs 
530c39f472eSBen Skeggs static inline u32
init_shift(u32 data,u8 shift)531c39f472eSBen Skeggs init_shift(u32 data, u8 shift)
532c39f472eSBen Skeggs {
533c39f472eSBen Skeggs 	if (shift < 0x80)
534c39f472eSBen Skeggs 		return data >> shift;
535c39f472eSBen Skeggs 	return data << (0x100 - shift);
536c39f472eSBen Skeggs }
537c39f472eSBen Skeggs 
538c39f472eSBen Skeggs static u32
init_tmds_reg(struct nvbios_init * init,u8 tmds)539c39f472eSBen Skeggs init_tmds_reg(struct nvbios_init *init, u8 tmds)
540c39f472eSBen Skeggs {
541c39f472eSBen Skeggs 	/* For mlv < 0x80, it is an index into a table of TMDS base addresses.
542c39f472eSBen Skeggs 	 * For mlv == 0x80 use the "or" value of the dcb_entry indexed by
543c39f472eSBen Skeggs 	 * CR58 for CR57 = 0 to index a table of offsets to the basic
544c39f472eSBen Skeggs 	 * 0x6808b0 address.
545c39f472eSBen Skeggs 	 * For mlv == 0x81 use the "or" value of the dcb_entry indexed by
546c39f472eSBen Skeggs 	 * CR58 for CR57 = 0 to index a table of offsets to the basic
547c39f472eSBen Skeggs 	 * 0x6808b0 address, and then flip the offset by 8.
548c39f472eSBen Skeggs 	 */
549c39f472eSBen Skeggs 	const int pramdac_offset[13] = {
550c39f472eSBen Skeggs 		0, 0, 0x8, 0, 0x2000, 0, 0, 0, 0x2008, 0, 0, 0, 0x2000 };
551c39f472eSBen Skeggs 	const u32 pramdac_table[4] = {
552c39f472eSBen Skeggs 		0x6808b0, 0x6808b8, 0x6828b0, 0x6828b8 };
553c39f472eSBen Skeggs 
554c39f472eSBen Skeggs 	if (tmds >= 0x80) {
555c39f472eSBen Skeggs 		if (init->outp) {
556c39f472eSBen Skeggs 			u32 dacoffset = pramdac_offset[init->outp->or];
557c39f472eSBen Skeggs 			if (tmds == 0x81)
558c39f472eSBen Skeggs 				dacoffset ^= 8;
559c39f472eSBen Skeggs 			return 0x6808b0 + dacoffset;
560c39f472eSBen Skeggs 		}
561c39f472eSBen Skeggs 
562c39f472eSBen Skeggs 		if (init_exec(init))
563c39f472eSBen Skeggs 			error("tmds opcodes need dcb\n");
564c39f472eSBen Skeggs 	} else {
565c39f472eSBen Skeggs 		if (tmds < ARRAY_SIZE(pramdac_table))
566c39f472eSBen Skeggs 			return pramdac_table[tmds];
567c39f472eSBen Skeggs 
568c39f472eSBen Skeggs 		error("tmds selector 0x%02x unknown\n", tmds);
569c39f472eSBen Skeggs 	}
570c39f472eSBen Skeggs 
571c39f472eSBen Skeggs 	return 0;
572c39f472eSBen Skeggs }
573c39f472eSBen Skeggs 
574c39f472eSBen Skeggs /******************************************************************************
575c39f472eSBen Skeggs  * init opcode handlers
576c39f472eSBen Skeggs  *****************************************************************************/
577c39f472eSBen Skeggs 
578c39f472eSBen Skeggs /**
579c39f472eSBen Skeggs  * init_reserved - stub for various unknown/unused single-byte opcodes
580c39f472eSBen Skeggs  *
581c39f472eSBen Skeggs  */
582c39f472eSBen Skeggs static void
init_reserved(struct nvbios_init * init)583c39f472eSBen Skeggs init_reserved(struct nvbios_init *init)
584c39f472eSBen Skeggs {
5855b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
5865b0e787aSBen Skeggs 	u8 opcode = nvbios_rd08(bios, init->offset);
587c39f472eSBen Skeggs 	u8 length, i;
588c39f472eSBen Skeggs 
589c39f472eSBen Skeggs 	switch (opcode) {
590c39f472eSBen Skeggs 	case 0xaa:
591c39f472eSBen Skeggs 		length = 4;
592c39f472eSBen Skeggs 		break;
593c39f472eSBen Skeggs 	default:
594c39f472eSBen Skeggs 		length = 1;
595c39f472eSBen Skeggs 		break;
596c39f472eSBen Skeggs 	}
597c39f472eSBen Skeggs 
598c39f472eSBen Skeggs 	trace("RESERVED 0x%02x\t", opcode);
599c39f472eSBen Skeggs 	for (i = 1; i < length; i++)
6005b0e787aSBen Skeggs 		cont(" 0x%02x", nvbios_rd08(bios, init->offset + i));
601c39f472eSBen Skeggs 	cont("\n");
602c39f472eSBen Skeggs 	init->offset += length;
603c39f472eSBen Skeggs }
604c39f472eSBen Skeggs 
605c39f472eSBen Skeggs /**
606c39f472eSBen Skeggs  * INIT_DONE - opcode 0x71
607c39f472eSBen Skeggs  *
608c39f472eSBen Skeggs  */
609c39f472eSBen Skeggs static void
init_done(struct nvbios_init * init)610c39f472eSBen Skeggs init_done(struct nvbios_init *init)
611c39f472eSBen Skeggs {
612c39f472eSBen Skeggs 	trace("DONE\n");
613c39f472eSBen Skeggs 	init->offset = 0x0000;
614c39f472eSBen Skeggs }
615c39f472eSBen Skeggs 
616c39f472eSBen Skeggs /**
617c39f472eSBen Skeggs  * INIT_IO_RESTRICT_PROG - opcode 0x32
618c39f472eSBen Skeggs  *
619c39f472eSBen Skeggs  */
620c39f472eSBen Skeggs static void
init_io_restrict_prog(struct nvbios_init * init)621c39f472eSBen Skeggs init_io_restrict_prog(struct nvbios_init *init)
622c39f472eSBen Skeggs {
6235b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
6247f5f518fSBen Skeggs 	u16 port = nvbios_rd16(bios, init->offset + 1);
6257f5f518fSBen Skeggs 	u8 index = nvbios_rd08(bios, init->offset + 3);
6267f5f518fSBen Skeggs 	u8  mask = nvbios_rd08(bios, init->offset + 4);
6277f5f518fSBen Skeggs 	u8 shift = nvbios_rd08(bios, init->offset + 5);
6287f5f518fSBen Skeggs 	u8 count = nvbios_rd08(bios, init->offset + 6);
6297f5f518fSBen Skeggs 	u32  reg = nvbios_rd32(bios, init->offset + 7);
630c39f472eSBen Skeggs 	u8 conf, i;
631c39f472eSBen Skeggs 
632c39f472eSBen Skeggs 	trace("IO_RESTRICT_PROG\tR[0x%06x] = "
633c39f472eSBen Skeggs 	      "((0x%04x[0x%02x] & 0x%02x) >> %d) [{\n",
634c39f472eSBen Skeggs 	      reg, port, index, mask, shift);
635c39f472eSBen Skeggs 	init->offset += 11;
636c39f472eSBen Skeggs 
637c39f472eSBen Skeggs 	conf = (init_rdvgai(init, port, index) & mask) >> shift;
638c39f472eSBen Skeggs 	for (i = 0; i < count; i++) {
6397f5f518fSBen Skeggs 		u32 data = nvbios_rd32(bios, init->offset);
640c39f472eSBen Skeggs 
641c39f472eSBen Skeggs 		if (i == conf) {
642c39f472eSBen Skeggs 			trace("\t0x%08x *\n", data);
643c39f472eSBen Skeggs 			init_wr32(init, reg, data);
644c39f472eSBen Skeggs 		} else {
645c39f472eSBen Skeggs 			trace("\t0x%08x\n", data);
646c39f472eSBen Skeggs 		}
647c39f472eSBen Skeggs 
648c39f472eSBen Skeggs 		init->offset += 4;
649c39f472eSBen Skeggs 	}
650c39f472eSBen Skeggs 	trace("}]\n");
651c39f472eSBen Skeggs }
652c39f472eSBen Skeggs 
653c39f472eSBen Skeggs /**
654c39f472eSBen Skeggs  * INIT_REPEAT - opcode 0x33
655c39f472eSBen Skeggs  *
656c39f472eSBen Skeggs  */
657c39f472eSBen Skeggs static void
init_repeat(struct nvbios_init * init)658c39f472eSBen Skeggs init_repeat(struct nvbios_init *init)
659c39f472eSBen Skeggs {
6605b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
6617f5f518fSBen Skeggs 	u8 count = nvbios_rd08(bios, init->offset + 1);
662c39f472eSBen Skeggs 	u16 repeat = init->repeat;
663c39f472eSBen Skeggs 
664c39f472eSBen Skeggs 	trace("REPEAT\t0x%02x\n", count);
665c39f472eSBen Skeggs 	init->offset += 2;
666c39f472eSBen Skeggs 
667c39f472eSBen Skeggs 	init->repeat = init->offset;
668c39f472eSBen Skeggs 	init->repend = init->offset;
669c39f472eSBen Skeggs 	while (count--) {
670c39f472eSBen Skeggs 		init->offset = init->repeat;
671c39f472eSBen Skeggs 		nvbios_exec(init);
672c39f472eSBen Skeggs 		if (count)
673c39f472eSBen Skeggs 			trace("REPEAT\t0x%02x\n", count);
674c39f472eSBen Skeggs 	}
675c39f472eSBen Skeggs 	init->offset = init->repend;
676c39f472eSBen Skeggs 	init->repeat = repeat;
677c39f472eSBen Skeggs }
678c39f472eSBen Skeggs 
679c39f472eSBen Skeggs /**
680c39f472eSBen Skeggs  * INIT_IO_RESTRICT_PLL - opcode 0x34
681c39f472eSBen Skeggs  *
682c39f472eSBen Skeggs  */
683c39f472eSBen Skeggs static void
init_io_restrict_pll(struct nvbios_init * init)684c39f472eSBen Skeggs init_io_restrict_pll(struct nvbios_init *init)
685c39f472eSBen Skeggs {
6865b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
6877f5f518fSBen Skeggs 	u16 port = nvbios_rd16(bios, init->offset + 1);
6887f5f518fSBen Skeggs 	u8 index = nvbios_rd08(bios, init->offset + 3);
6897f5f518fSBen Skeggs 	u8  mask = nvbios_rd08(bios, init->offset + 4);
6907f5f518fSBen Skeggs 	u8 shift = nvbios_rd08(bios, init->offset + 5);
6917f5f518fSBen Skeggs 	s8  iofc = nvbios_rd08(bios, init->offset + 6);
6927f5f518fSBen Skeggs 	u8 count = nvbios_rd08(bios, init->offset + 7);
6937f5f518fSBen Skeggs 	u32  reg = nvbios_rd32(bios, init->offset + 8);
694c39f472eSBen Skeggs 	u8 conf, i;
695c39f472eSBen Skeggs 
696c39f472eSBen Skeggs 	trace("IO_RESTRICT_PLL\tR[0x%06x] =PLL= "
697c39f472eSBen Skeggs 	      "((0x%04x[0x%02x] & 0x%02x) >> 0x%02x) IOFCOND 0x%02x [{\n",
698c39f472eSBen Skeggs 	      reg, port, index, mask, shift, iofc);
699c39f472eSBen Skeggs 	init->offset += 12;
700c39f472eSBen Skeggs 
701c39f472eSBen Skeggs 	conf = (init_rdvgai(init, port, index) & mask) >> shift;
702c39f472eSBen Skeggs 	for (i = 0; i < count; i++) {
7037f5f518fSBen Skeggs 		u32 freq = nvbios_rd16(bios, init->offset) * 10;
704c39f472eSBen Skeggs 
705c39f472eSBen Skeggs 		if (i == conf) {
706c39f472eSBen Skeggs 			trace("\t%dkHz *\n", freq);
707c39f472eSBen Skeggs 			if (iofc > 0 && init_io_flag_condition_met(init, iofc))
708c39f472eSBen Skeggs 				freq *= 2;
709c39f472eSBen Skeggs 			init_prog_pll(init, reg, freq);
710c39f472eSBen Skeggs 		} else {
711c39f472eSBen Skeggs 			trace("\t%dkHz\n", freq);
712c39f472eSBen Skeggs 		}
713c39f472eSBen Skeggs 
714c39f472eSBen Skeggs 		init->offset += 2;
715c39f472eSBen Skeggs 	}
716c39f472eSBen Skeggs 	trace("}]\n");
717c39f472eSBen Skeggs }
718c39f472eSBen Skeggs 
719c39f472eSBen Skeggs /**
720c39f472eSBen Skeggs  * INIT_END_REPEAT - opcode 0x36
721c39f472eSBen Skeggs  *
722c39f472eSBen Skeggs  */
723c39f472eSBen Skeggs static void
init_end_repeat(struct nvbios_init * init)724c39f472eSBen Skeggs init_end_repeat(struct nvbios_init *init)
725c39f472eSBen Skeggs {
726c39f472eSBen Skeggs 	trace("END_REPEAT\n");
727c39f472eSBen Skeggs 	init->offset += 1;
728c39f472eSBen Skeggs 
729c39f472eSBen Skeggs 	if (init->repeat) {
730c39f472eSBen Skeggs 		init->repend = init->offset;
731c39f472eSBen Skeggs 		init->offset = 0;
732c39f472eSBen Skeggs 	}
733c39f472eSBen Skeggs }
734c39f472eSBen Skeggs 
735c39f472eSBen Skeggs /**
736c39f472eSBen Skeggs  * INIT_COPY - opcode 0x37
737c39f472eSBen Skeggs  *
738c39f472eSBen Skeggs  */
739c39f472eSBen Skeggs static void
init_copy(struct nvbios_init * init)740c39f472eSBen Skeggs init_copy(struct nvbios_init *init)
741c39f472eSBen Skeggs {
7425b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
7437f5f518fSBen Skeggs 	u32  reg = nvbios_rd32(bios, init->offset + 1);
7447f5f518fSBen Skeggs 	u8 shift = nvbios_rd08(bios, init->offset + 5);
7457f5f518fSBen Skeggs 	u8 smask = nvbios_rd08(bios, init->offset + 6);
7467f5f518fSBen Skeggs 	u16 port = nvbios_rd16(bios, init->offset + 7);
7477f5f518fSBen Skeggs 	u8 index = nvbios_rd08(bios, init->offset + 9);
7487f5f518fSBen Skeggs 	u8  mask = nvbios_rd08(bios, init->offset + 10);
749c39f472eSBen Skeggs 	u8  data;
750c39f472eSBen Skeggs 
751c39f472eSBen Skeggs 	trace("COPY\t0x%04x[0x%02x] &= 0x%02x |= "
752c39f472eSBen Skeggs 	      "((R[0x%06x] %s 0x%02x) & 0x%02x)\n",
753c39f472eSBen Skeggs 	      port, index, mask, reg, (shift & 0x80) ? "<<" : ">>",
754c39f472eSBen Skeggs 	      (shift & 0x80) ? (0x100 - shift) : shift, smask);
755c39f472eSBen Skeggs 	init->offset += 11;
756c39f472eSBen Skeggs 
757c39f472eSBen Skeggs 	data  = init_rdvgai(init, port, index) & mask;
758c39f472eSBen Skeggs 	data |= init_shift(init_rd32(init, reg), shift) & smask;
759c39f472eSBen Skeggs 	init_wrvgai(init, port, index, data);
760c39f472eSBen Skeggs }
761c39f472eSBen Skeggs 
762c39f472eSBen Skeggs /**
763c39f472eSBen Skeggs  * INIT_NOT - opcode 0x38
764c39f472eSBen Skeggs  *
765c39f472eSBen Skeggs  */
766c39f472eSBen Skeggs static void
init_not(struct nvbios_init * init)767c39f472eSBen Skeggs init_not(struct nvbios_init *init)
768c39f472eSBen Skeggs {
769c39f472eSBen Skeggs 	trace("NOT\n");
770c39f472eSBen Skeggs 	init->offset += 1;
771c39f472eSBen Skeggs 	init_exec_inv(init);
772c39f472eSBen Skeggs }
773c39f472eSBen Skeggs 
774c39f472eSBen Skeggs /**
775c39f472eSBen Skeggs  * INIT_IO_FLAG_CONDITION - opcode 0x39
776c39f472eSBen Skeggs  *
777c39f472eSBen Skeggs  */
778c39f472eSBen Skeggs static void
init_io_flag_condition(struct nvbios_init * init)779c39f472eSBen Skeggs init_io_flag_condition(struct nvbios_init *init)
780c39f472eSBen Skeggs {
7815b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
7827f5f518fSBen Skeggs 	u8 cond = nvbios_rd08(bios, init->offset + 1);
783c39f472eSBen Skeggs 
784c39f472eSBen Skeggs 	trace("IO_FLAG_CONDITION\t0x%02x\n", cond);
785c39f472eSBen Skeggs 	init->offset += 2;
786c39f472eSBen Skeggs 
787c39f472eSBen Skeggs 	if (!init_io_flag_condition_met(init, cond))
788c39f472eSBen Skeggs 		init_exec_set(init, false);
789c39f472eSBen Skeggs }
790c39f472eSBen Skeggs 
791c39f472eSBen Skeggs /**
792989f5784SBen Skeggs  * INIT_GENERIC_CONDITION - opcode 0x3a
793c39f472eSBen Skeggs  *
794c39f472eSBen Skeggs  */
795c39f472eSBen Skeggs static void
init_generic_condition(struct nvbios_init * init)796989f5784SBen Skeggs init_generic_condition(struct nvbios_init *init)
797c39f472eSBen Skeggs {
7985b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
799c39f472eSBen Skeggs 	struct nvbios_dpout info;
8007f5f518fSBen Skeggs 	u8  cond = nvbios_rd08(bios, init->offset + 1);
801e24c9c44SBen Skeggs 	u8  size = nvbios_rd08(bios, init->offset + 2);
802c39f472eSBen Skeggs 	u8  ver, hdr, cnt, len;
803c39f472eSBen Skeggs 	u16 data;
804c39f472eSBen Skeggs 
805e24c9c44SBen Skeggs 	trace("GENERIC_CONDITION\t0x%02x 0x%02x\n", cond, size);
806c39f472eSBen Skeggs 	init->offset += 3;
807c39f472eSBen Skeggs 
808c39f472eSBen Skeggs 	switch (cond) {
80981f2bb5dSBen Skeggs 	case 0: /* CONDITION_ID_INT_DP. */
810c39f472eSBen Skeggs 		if (init_conn(init) != DCB_CONNECTOR_eDP)
811c39f472eSBen Skeggs 			init_exec_set(init, false);
812c39f472eSBen Skeggs 		break;
81381f2bb5dSBen Skeggs 	case 1: /* CONDITION_ID_USE_SPPLL0. */
81481f2bb5dSBen Skeggs 	case 2: /* CONDITION_ID_USE_SPPLL1. */
815c39f472eSBen Skeggs 		if ( init->outp &&
816c39f472eSBen Skeggs 		    (data = nvbios_dpout_match(bios, DCB_OUTPUT_DP,
817c39f472eSBen Skeggs 					       (init->outp->or << 0) |
818c39f472eSBen Skeggs 					       (init->outp->sorconf.link << 6),
819c39f472eSBen Skeggs 					       &ver, &hdr, &cnt, &len, &info)))
820c39f472eSBen Skeggs 		{
821c39f472eSBen Skeggs 			if (!(info.flags & cond))
822c39f472eSBen Skeggs 				init_exec_set(init, false);
823c39f472eSBen Skeggs 			break;
824c39f472eSBen Skeggs 		}
825c39f472eSBen Skeggs 
826c39f472eSBen Skeggs 		if (init_exec(init))
827c39f472eSBen Skeggs 			warn("script needs dp output table data\n");
828c39f472eSBen Skeggs 		break;
82981f2bb5dSBen Skeggs 	case 5: /* CONDITION_ID_ASSR_SUPPORT. */
830c39f472eSBen Skeggs 		if (!(init_rdauxr(init, 0x0d) & 1))
831c39f472eSBen Skeggs 			init_exec_set(init, false);
832c39f472eSBen Skeggs 		break;
833eb972d14SBen Skeggs 	case 7: /* CONDITION_ID_NO_PANEL_SEQ_DELAYS. */
834eb972d14SBen Skeggs 		init_exec_set(init, false);
835eb972d14SBen Skeggs 		break;
836c39f472eSBen Skeggs 	default:
837fcca420dSColin Ian King 		warn("INIT_GENERIC_CONDITION: unknown 0x%02x\n", cond);
838e24c9c44SBen Skeggs 		init->offset += size;
839c39f472eSBen Skeggs 		break;
840c39f472eSBen Skeggs 	}
841c39f472eSBen Skeggs }
842c39f472eSBen Skeggs 
843c39f472eSBen Skeggs /**
844c39f472eSBen Skeggs  * INIT_IO_MASK_OR - opcode 0x3b
845c39f472eSBen Skeggs  *
846c39f472eSBen Skeggs  */
847c39f472eSBen Skeggs static void
init_io_mask_or(struct nvbios_init * init)848c39f472eSBen Skeggs init_io_mask_or(struct nvbios_init *init)
849c39f472eSBen Skeggs {
8505b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
8517f5f518fSBen Skeggs 	u8 index = nvbios_rd08(bios, init->offset + 1);
852c39f472eSBen Skeggs 	u8    or = init_or(init);
853c39f472eSBen Skeggs 	u8  data;
854c39f472eSBen Skeggs 
855c39f472eSBen Skeggs 	trace("IO_MASK_OR\t0x03d4[0x%02x] &= ~(1 << 0x%02x)\n", index, or);
856c39f472eSBen Skeggs 	init->offset += 2;
857c39f472eSBen Skeggs 
858c39f472eSBen Skeggs 	data = init_rdvgai(init, 0x03d4, index);
859c39f472eSBen Skeggs 	init_wrvgai(init, 0x03d4, index, data &= ~(1 << or));
860c39f472eSBen Skeggs }
861c39f472eSBen Skeggs 
862c39f472eSBen Skeggs /**
863c39f472eSBen Skeggs  * INIT_IO_OR - opcode 0x3c
864c39f472eSBen Skeggs  *
865c39f472eSBen Skeggs  */
866c39f472eSBen Skeggs static void
init_io_or(struct nvbios_init * init)867c39f472eSBen Skeggs init_io_or(struct nvbios_init *init)
868c39f472eSBen Skeggs {
8695b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
8707f5f518fSBen Skeggs 	u8 index = nvbios_rd08(bios, init->offset + 1);
871c39f472eSBen Skeggs 	u8    or = init_or(init);
872c39f472eSBen Skeggs 	u8  data;
873c39f472eSBen Skeggs 
874c39f472eSBen Skeggs 	trace("IO_OR\t0x03d4[0x%02x] |= (1 << 0x%02x)\n", index, or);
875c39f472eSBen Skeggs 	init->offset += 2;
876c39f472eSBen Skeggs 
877c39f472eSBen Skeggs 	data = init_rdvgai(init, 0x03d4, index);
878c39f472eSBen Skeggs 	init_wrvgai(init, 0x03d4, index, data | (1 << or));
879c39f472eSBen Skeggs }
880c39f472eSBen Skeggs 
881c39f472eSBen Skeggs /**
882c39f472eSBen Skeggs  * INIT_ANDN_REG - opcode 0x47
883c39f472eSBen Skeggs  *
884c39f472eSBen Skeggs  */
885c39f472eSBen Skeggs static void
init_andn_reg(struct nvbios_init * init)886c39f472eSBen Skeggs init_andn_reg(struct nvbios_init *init)
887c39f472eSBen Skeggs {
8885b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
8897f5f518fSBen Skeggs 	u32  reg = nvbios_rd32(bios, init->offset + 1);
8907f5f518fSBen Skeggs 	u32 mask = nvbios_rd32(bios, init->offset + 5);
891c39f472eSBen Skeggs 
892c39f472eSBen Skeggs 	trace("ANDN_REG\tR[0x%06x] &= ~0x%08x\n", reg, mask);
893c39f472eSBen Skeggs 	init->offset += 9;
894c39f472eSBen Skeggs 
895c39f472eSBen Skeggs 	init_mask(init, reg, mask, 0);
896c39f472eSBen Skeggs }
897c39f472eSBen Skeggs 
898c39f472eSBen Skeggs /**
899c39f472eSBen Skeggs  * INIT_OR_REG - opcode 0x48
900c39f472eSBen Skeggs  *
901c39f472eSBen Skeggs  */
902c39f472eSBen Skeggs static void
init_or_reg(struct nvbios_init * init)903c39f472eSBen Skeggs init_or_reg(struct nvbios_init *init)
904c39f472eSBen Skeggs {
9055b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
9067f5f518fSBen Skeggs 	u32  reg = nvbios_rd32(bios, init->offset + 1);
9077f5f518fSBen Skeggs 	u32 mask = nvbios_rd32(bios, init->offset + 5);
908c39f472eSBen Skeggs 
909c39f472eSBen Skeggs 	trace("OR_REG\tR[0x%06x] |= 0x%08x\n", reg, mask);
910c39f472eSBen Skeggs 	init->offset += 9;
911c39f472eSBen Skeggs 
912c39f472eSBen Skeggs 	init_mask(init, reg, 0, mask);
913c39f472eSBen Skeggs }
914c39f472eSBen Skeggs 
915c39f472eSBen Skeggs /**
916c39f472eSBen Skeggs  * INIT_INDEX_ADDRESS_LATCHED - opcode 0x49
917c39f472eSBen Skeggs  *
918c39f472eSBen Skeggs  */
919c39f472eSBen Skeggs static void
init_idx_addr_latched(struct nvbios_init * init)920c39f472eSBen Skeggs init_idx_addr_latched(struct nvbios_init *init)
921c39f472eSBen Skeggs {
9225b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
9237f5f518fSBen Skeggs 	u32 creg = nvbios_rd32(bios, init->offset + 1);
9247f5f518fSBen Skeggs 	u32 dreg = nvbios_rd32(bios, init->offset + 5);
9257f5f518fSBen Skeggs 	u32 mask = nvbios_rd32(bios, init->offset + 9);
9267f5f518fSBen Skeggs 	u32 data = nvbios_rd32(bios, init->offset + 13);
9277f5f518fSBen Skeggs 	u8 count = nvbios_rd08(bios, init->offset + 17);
928c39f472eSBen Skeggs 
929c39f472eSBen Skeggs 	trace("INDEX_ADDRESS_LATCHED\tR[0x%06x] : R[0x%06x]\n", creg, dreg);
930c39f472eSBen Skeggs 	trace("\tCTRL &= 0x%08x |= 0x%08x\n", mask, data);
931c39f472eSBen Skeggs 	init->offset += 18;
932c39f472eSBen Skeggs 
933c39f472eSBen Skeggs 	while (count--) {
9347f5f518fSBen Skeggs 		u8 iaddr = nvbios_rd08(bios, init->offset + 0);
9357f5f518fSBen Skeggs 		u8 idata = nvbios_rd08(bios, init->offset + 1);
936c39f472eSBen Skeggs 
937c39f472eSBen Skeggs 		trace("\t[0x%02x] = 0x%02x\n", iaddr, idata);
938c39f472eSBen Skeggs 		init->offset += 2;
939c39f472eSBen Skeggs 
940c39f472eSBen Skeggs 		init_wr32(init, dreg, idata);
941c39f472eSBen Skeggs 		init_mask(init, creg, ~mask, data | iaddr);
942c39f472eSBen Skeggs 	}
943c39f472eSBen Skeggs }
944c39f472eSBen Skeggs 
945c39f472eSBen Skeggs /**
946c39f472eSBen Skeggs  * INIT_IO_RESTRICT_PLL2 - opcode 0x4a
947c39f472eSBen Skeggs  *
948c39f472eSBen Skeggs  */
949c39f472eSBen Skeggs static void
init_io_restrict_pll2(struct nvbios_init * init)950c39f472eSBen Skeggs init_io_restrict_pll2(struct nvbios_init *init)
951c39f472eSBen Skeggs {
9525b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
9537f5f518fSBen Skeggs 	u16 port = nvbios_rd16(bios, init->offset + 1);
9547f5f518fSBen Skeggs 	u8 index = nvbios_rd08(bios, init->offset + 3);
9557f5f518fSBen Skeggs 	u8  mask = nvbios_rd08(bios, init->offset + 4);
9567f5f518fSBen Skeggs 	u8 shift = nvbios_rd08(bios, init->offset + 5);
9577f5f518fSBen Skeggs 	u8 count = nvbios_rd08(bios, init->offset + 6);
9587f5f518fSBen Skeggs 	u32  reg = nvbios_rd32(bios, init->offset + 7);
959c39f472eSBen Skeggs 	u8  conf, i;
960c39f472eSBen Skeggs 
961c39f472eSBen Skeggs 	trace("IO_RESTRICT_PLL2\t"
962c39f472eSBen Skeggs 	      "R[0x%06x] =PLL= ((0x%04x[0x%02x] & 0x%02x) >> 0x%02x) [{\n",
963c39f472eSBen Skeggs 	      reg, port, index, mask, shift);
964c39f472eSBen Skeggs 	init->offset += 11;
965c39f472eSBen Skeggs 
966c39f472eSBen Skeggs 	conf = (init_rdvgai(init, port, index) & mask) >> shift;
967c39f472eSBen Skeggs 	for (i = 0; i < count; i++) {
9687f5f518fSBen Skeggs 		u32 freq = nvbios_rd32(bios, init->offset);
969c39f472eSBen Skeggs 		if (i == conf) {
970c39f472eSBen Skeggs 			trace("\t%dkHz *\n", freq);
971c39f472eSBen Skeggs 			init_prog_pll(init, reg, freq);
972c39f472eSBen Skeggs 		} else {
973c39f472eSBen Skeggs 			trace("\t%dkHz\n", freq);
974c39f472eSBen Skeggs 		}
975c39f472eSBen Skeggs 		init->offset += 4;
976c39f472eSBen Skeggs 	}
977c39f472eSBen Skeggs 	trace("}]\n");
978c39f472eSBen Skeggs }
979c39f472eSBen Skeggs 
980c39f472eSBen Skeggs /**
981c39f472eSBen Skeggs  * INIT_PLL2 - opcode 0x4b
982c39f472eSBen Skeggs  *
983c39f472eSBen Skeggs  */
984c39f472eSBen Skeggs static void
init_pll2(struct nvbios_init * init)985c39f472eSBen Skeggs init_pll2(struct nvbios_init *init)
986c39f472eSBen Skeggs {
9875b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
9887f5f518fSBen Skeggs 	u32  reg = nvbios_rd32(bios, init->offset + 1);
9897f5f518fSBen Skeggs 	u32 freq = nvbios_rd32(bios, init->offset + 5);
990c39f472eSBen Skeggs 
991c39f472eSBen Skeggs 	trace("PLL2\tR[0x%06x] =PLL= %dkHz\n", reg, freq);
992c39f472eSBen Skeggs 	init->offset += 9;
993c39f472eSBen Skeggs 
994c39f472eSBen Skeggs 	init_prog_pll(init, reg, freq);
995c39f472eSBen Skeggs }
996c39f472eSBen Skeggs 
997c39f472eSBen Skeggs /**
998c39f472eSBen Skeggs  * INIT_I2C_BYTE - opcode 0x4c
999c39f472eSBen Skeggs  *
1000c39f472eSBen Skeggs  */
1001c39f472eSBen Skeggs static void
init_i2c_byte(struct nvbios_init * init)1002c39f472eSBen Skeggs init_i2c_byte(struct nvbios_init *init)
1003c39f472eSBen Skeggs {
10045b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
10057f5f518fSBen Skeggs 	u8 index = nvbios_rd08(bios, init->offset + 1);
10067f5f518fSBen Skeggs 	u8  addr = nvbios_rd08(bios, init->offset + 2) >> 1;
10077f5f518fSBen Skeggs 	u8 count = nvbios_rd08(bios, init->offset + 3);
1008c39f472eSBen Skeggs 
1009c39f472eSBen Skeggs 	trace("I2C_BYTE\tI2C[0x%02x][0x%02x]\n", index, addr);
1010c39f472eSBen Skeggs 	init->offset += 4;
1011c39f472eSBen Skeggs 
1012c39f472eSBen Skeggs 	while (count--) {
10137f5f518fSBen Skeggs 		u8  reg = nvbios_rd08(bios, init->offset + 0);
10147f5f518fSBen Skeggs 		u8 mask = nvbios_rd08(bios, init->offset + 1);
10157f5f518fSBen Skeggs 		u8 data = nvbios_rd08(bios, init->offset + 2);
1016c39f472eSBen Skeggs 		int val;
1017c39f472eSBen Skeggs 
1018c39f472eSBen Skeggs 		trace("\t[0x%02x] &= 0x%02x |= 0x%02x\n", reg, mask, data);
1019c39f472eSBen Skeggs 		init->offset += 3;
1020c39f472eSBen Skeggs 
1021c39f472eSBen Skeggs 		val = init_rdi2cr(init, index, addr, reg);
1022c39f472eSBen Skeggs 		if (val < 0)
1023c39f472eSBen Skeggs 			continue;
1024c39f472eSBen Skeggs 		init_wri2cr(init, index, addr, reg, (val & mask) | data);
1025c39f472eSBen Skeggs 	}
1026c39f472eSBen Skeggs }
1027c39f472eSBen Skeggs 
1028c39f472eSBen Skeggs /**
1029c39f472eSBen Skeggs  * INIT_ZM_I2C_BYTE - opcode 0x4d
1030c39f472eSBen Skeggs  *
1031c39f472eSBen Skeggs  */
1032c39f472eSBen Skeggs static void
init_zm_i2c_byte(struct nvbios_init * init)1033c39f472eSBen Skeggs init_zm_i2c_byte(struct nvbios_init *init)
1034c39f472eSBen Skeggs {
10355b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
10367f5f518fSBen Skeggs 	u8 index = nvbios_rd08(bios, init->offset + 1);
10377f5f518fSBen Skeggs 	u8  addr = nvbios_rd08(bios, init->offset + 2) >> 1;
10387f5f518fSBen Skeggs 	u8 count = nvbios_rd08(bios, init->offset + 3);
1039c39f472eSBen Skeggs 
1040c39f472eSBen Skeggs 	trace("ZM_I2C_BYTE\tI2C[0x%02x][0x%02x]\n", index, addr);
1041c39f472eSBen Skeggs 	init->offset += 4;
1042c39f472eSBen Skeggs 
1043c39f472eSBen Skeggs 	while (count--) {
10447f5f518fSBen Skeggs 		u8  reg = nvbios_rd08(bios, init->offset + 0);
10457f5f518fSBen Skeggs 		u8 data = nvbios_rd08(bios, init->offset + 1);
1046c39f472eSBen Skeggs 
1047c39f472eSBen Skeggs 		trace("\t[0x%02x] = 0x%02x\n", reg, data);
1048c39f472eSBen Skeggs 		init->offset += 2;
1049c39f472eSBen Skeggs 
1050c39f472eSBen Skeggs 		init_wri2cr(init, index, addr, reg, data);
1051c39f472eSBen Skeggs 	}
1052c39f472eSBen Skeggs }
1053c39f472eSBen Skeggs 
1054c39f472eSBen Skeggs /**
1055c39f472eSBen Skeggs  * INIT_ZM_I2C - opcode 0x4e
1056c39f472eSBen Skeggs  *
1057c39f472eSBen Skeggs  */
1058c39f472eSBen Skeggs static void
init_zm_i2c(struct nvbios_init * init)1059c39f472eSBen Skeggs init_zm_i2c(struct nvbios_init *init)
1060c39f472eSBen Skeggs {
10615b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
10627f5f518fSBen Skeggs 	u8 index = nvbios_rd08(bios, init->offset + 1);
10637f5f518fSBen Skeggs 	u8  addr = nvbios_rd08(bios, init->offset + 2) >> 1;
10647f5f518fSBen Skeggs 	u8 count = nvbios_rd08(bios, init->offset + 3);
1065c39f472eSBen Skeggs 	u8 data[256], i;
1066c39f472eSBen Skeggs 
1067c39f472eSBen Skeggs 	trace("ZM_I2C\tI2C[0x%02x][0x%02x]\n", index, addr);
1068c39f472eSBen Skeggs 	init->offset += 4;
1069c39f472eSBen Skeggs 
1070c39f472eSBen Skeggs 	for (i = 0; i < count; i++) {
10717f5f518fSBen Skeggs 		data[i] = nvbios_rd08(bios, init->offset);
1072c39f472eSBen Skeggs 		trace("\t0x%02x\n", data[i]);
1073c39f472eSBen Skeggs 		init->offset++;
1074c39f472eSBen Skeggs 	}
1075c39f472eSBen Skeggs 
1076c39f472eSBen Skeggs 	if (init_exec(init)) {
10772aa5eac5SBen Skeggs 		struct i2c_adapter *adap = init_i2c(init, index);
1078c39f472eSBen Skeggs 		struct i2c_msg msg = {
1079c39f472eSBen Skeggs 			.addr = addr, .flags = 0, .len = count, .buf = data,
1080c39f472eSBen Skeggs 		};
1081c39f472eSBen Skeggs 		int ret;
1082c39f472eSBen Skeggs 
10832aa5eac5SBen Skeggs 		if (adap && (ret = i2c_transfer(adap, &msg, 1)) != 1)
1084c39f472eSBen Skeggs 			warn("i2c wr failed, %d\n", ret);
1085c39f472eSBen Skeggs 	}
1086c39f472eSBen Skeggs }
1087c39f472eSBen Skeggs 
1088c39f472eSBen Skeggs /**
1089c39f472eSBen Skeggs  * INIT_TMDS - opcode 0x4f
1090c39f472eSBen Skeggs  *
1091c39f472eSBen Skeggs  */
1092c39f472eSBen Skeggs static void
init_tmds(struct nvbios_init * init)1093c39f472eSBen Skeggs init_tmds(struct nvbios_init *init)
1094c39f472eSBen Skeggs {
10955b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
10967f5f518fSBen Skeggs 	u8 tmds = nvbios_rd08(bios, init->offset + 1);
10977f5f518fSBen Skeggs 	u8 addr = nvbios_rd08(bios, init->offset + 2);
10987f5f518fSBen Skeggs 	u8 mask = nvbios_rd08(bios, init->offset + 3);
10997f5f518fSBen Skeggs 	u8 data = nvbios_rd08(bios, init->offset + 4);
1100c39f472eSBen Skeggs 	u32 reg = init_tmds_reg(init, tmds);
1101c39f472eSBen Skeggs 
1102c39f472eSBen Skeggs 	trace("TMDS\tT[0x%02x][0x%02x] &= 0x%02x |= 0x%02x\n",
1103c39f472eSBen Skeggs 	      tmds, addr, mask, data);
1104c39f472eSBen Skeggs 	init->offset += 5;
1105c39f472eSBen Skeggs 
1106c39f472eSBen Skeggs 	if (reg == 0)
1107c39f472eSBen Skeggs 		return;
1108c39f472eSBen Skeggs 
1109c39f472eSBen Skeggs 	init_wr32(init, reg + 0, addr | 0x00010000);
1110c39f472eSBen Skeggs 	init_wr32(init, reg + 4, data | (init_rd32(init, reg + 4) & mask));
1111c39f472eSBen Skeggs 	init_wr32(init, reg + 0, addr);
1112c39f472eSBen Skeggs }
1113c39f472eSBen Skeggs 
1114c39f472eSBen Skeggs /**
1115c39f472eSBen Skeggs  * INIT_ZM_TMDS_GROUP - opcode 0x50
1116c39f472eSBen Skeggs  *
1117c39f472eSBen Skeggs  */
1118c39f472eSBen Skeggs static void
init_zm_tmds_group(struct nvbios_init * init)1119c39f472eSBen Skeggs init_zm_tmds_group(struct nvbios_init *init)
1120c39f472eSBen Skeggs {
11215b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
11227f5f518fSBen Skeggs 	u8  tmds = nvbios_rd08(bios, init->offset + 1);
11237f5f518fSBen Skeggs 	u8 count = nvbios_rd08(bios, init->offset + 2);
1124c39f472eSBen Skeggs 	u32  reg = init_tmds_reg(init, tmds);
1125c39f472eSBen Skeggs 
1126c39f472eSBen Skeggs 	trace("TMDS_ZM_GROUP\tT[0x%02x]\n", tmds);
1127c39f472eSBen Skeggs 	init->offset += 3;
1128c39f472eSBen Skeggs 
1129c39f472eSBen Skeggs 	while (count--) {
11307f5f518fSBen Skeggs 		u8 addr = nvbios_rd08(bios, init->offset + 0);
11317f5f518fSBen Skeggs 		u8 data = nvbios_rd08(bios, init->offset + 1);
1132c39f472eSBen Skeggs 
1133c39f472eSBen Skeggs 		trace("\t[0x%02x] = 0x%02x\n", addr, data);
1134c39f472eSBen Skeggs 		init->offset += 2;
1135c39f472eSBen Skeggs 
1136c39f472eSBen Skeggs 		init_wr32(init, reg + 4, data);
1137c39f472eSBen Skeggs 		init_wr32(init, reg + 0, addr);
1138c39f472eSBen Skeggs 	}
1139c39f472eSBen Skeggs }
1140c39f472eSBen Skeggs 
1141c39f472eSBen Skeggs /**
1142c39f472eSBen Skeggs  * INIT_CR_INDEX_ADDRESS_LATCHED - opcode 0x51
1143c39f472eSBen Skeggs  *
1144c39f472eSBen Skeggs  */
1145c39f472eSBen Skeggs static void
init_cr_idx_adr_latch(struct nvbios_init * init)1146c39f472eSBen Skeggs init_cr_idx_adr_latch(struct nvbios_init *init)
1147c39f472eSBen Skeggs {
11485b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
11497f5f518fSBen Skeggs 	u8 addr0 = nvbios_rd08(bios, init->offset + 1);
11507f5f518fSBen Skeggs 	u8 addr1 = nvbios_rd08(bios, init->offset + 2);
11517f5f518fSBen Skeggs 	u8  base = nvbios_rd08(bios, init->offset + 3);
11527f5f518fSBen Skeggs 	u8 count = nvbios_rd08(bios, init->offset + 4);
1153c39f472eSBen Skeggs 	u8 save0;
1154c39f472eSBen Skeggs 
1155c39f472eSBen Skeggs 	trace("CR_INDEX_ADDR C[%02x] C[%02x]\n", addr0, addr1);
1156c39f472eSBen Skeggs 	init->offset += 5;
1157c39f472eSBen Skeggs 
1158c39f472eSBen Skeggs 	save0 = init_rdvgai(init, 0x03d4, addr0);
1159c39f472eSBen Skeggs 	while (count--) {
11607f5f518fSBen Skeggs 		u8 data = nvbios_rd08(bios, init->offset);
1161c39f472eSBen Skeggs 
1162c39f472eSBen Skeggs 		trace("\t\t[0x%02x] = 0x%02x\n", base, data);
1163c39f472eSBen Skeggs 		init->offset += 1;
1164c39f472eSBen Skeggs 
1165c39f472eSBen Skeggs 		init_wrvgai(init, 0x03d4, addr0, base++);
1166c39f472eSBen Skeggs 		init_wrvgai(init, 0x03d4, addr1, data);
1167c39f472eSBen Skeggs 	}
1168c39f472eSBen Skeggs 	init_wrvgai(init, 0x03d4, addr0, save0);
1169c39f472eSBen Skeggs }
1170c39f472eSBen Skeggs 
1171c39f472eSBen Skeggs /**
1172c39f472eSBen Skeggs  * INIT_CR - opcode 0x52
1173c39f472eSBen Skeggs  *
1174c39f472eSBen Skeggs  */
1175c39f472eSBen Skeggs static void
init_cr(struct nvbios_init * init)1176c39f472eSBen Skeggs init_cr(struct nvbios_init *init)
1177c39f472eSBen Skeggs {
11785b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
11797f5f518fSBen Skeggs 	u8 addr = nvbios_rd08(bios, init->offset + 1);
11807f5f518fSBen Skeggs 	u8 mask = nvbios_rd08(bios, init->offset + 2);
11817f5f518fSBen Skeggs 	u8 data = nvbios_rd08(bios, init->offset + 3);
1182c39f472eSBen Skeggs 	u8 val;
1183c39f472eSBen Skeggs 
1184c39f472eSBen Skeggs 	trace("CR\t\tC[0x%02x] &= 0x%02x |= 0x%02x\n", addr, mask, data);
1185c39f472eSBen Skeggs 	init->offset += 4;
1186c39f472eSBen Skeggs 
1187c39f472eSBen Skeggs 	val = init_rdvgai(init, 0x03d4, addr) & mask;
1188c39f472eSBen Skeggs 	init_wrvgai(init, 0x03d4, addr, val | data);
1189c39f472eSBen Skeggs }
1190c39f472eSBen Skeggs 
1191c39f472eSBen Skeggs /**
1192c39f472eSBen Skeggs  * INIT_ZM_CR - opcode 0x53
1193c39f472eSBen Skeggs  *
1194c39f472eSBen Skeggs  */
1195c39f472eSBen Skeggs static void
init_zm_cr(struct nvbios_init * init)1196c39f472eSBen Skeggs init_zm_cr(struct nvbios_init *init)
1197c39f472eSBen Skeggs {
11985b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
11997f5f518fSBen Skeggs 	u8 addr = nvbios_rd08(bios, init->offset + 1);
12007f5f518fSBen Skeggs 	u8 data = nvbios_rd08(bios, init->offset + 2);
1201c39f472eSBen Skeggs 
1202c39f472eSBen Skeggs 	trace("ZM_CR\tC[0x%02x] = 0x%02x\n", addr,  data);
1203c39f472eSBen Skeggs 	init->offset += 3;
1204c39f472eSBen Skeggs 
1205c39f472eSBen Skeggs 	init_wrvgai(init, 0x03d4, addr, data);
1206c39f472eSBen Skeggs }
1207c39f472eSBen Skeggs 
1208c39f472eSBen Skeggs /**
1209c39f472eSBen Skeggs  * INIT_ZM_CR_GROUP - opcode 0x54
1210c39f472eSBen Skeggs  *
1211c39f472eSBen Skeggs  */
1212c39f472eSBen Skeggs static void
init_zm_cr_group(struct nvbios_init * init)1213c39f472eSBen Skeggs init_zm_cr_group(struct nvbios_init *init)
1214c39f472eSBen Skeggs {
12155b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
12167f5f518fSBen Skeggs 	u8 count = nvbios_rd08(bios, init->offset + 1);
1217c39f472eSBen Skeggs 
1218c39f472eSBen Skeggs 	trace("ZM_CR_GROUP\n");
1219c39f472eSBen Skeggs 	init->offset += 2;
1220c39f472eSBen Skeggs 
1221c39f472eSBen Skeggs 	while (count--) {
12227f5f518fSBen Skeggs 		u8 addr = nvbios_rd08(bios, init->offset + 0);
12237f5f518fSBen Skeggs 		u8 data = nvbios_rd08(bios, init->offset + 1);
1224c39f472eSBen Skeggs 
1225c39f472eSBen Skeggs 		trace("\t\tC[0x%02x] = 0x%02x\n", addr, data);
1226c39f472eSBen Skeggs 		init->offset += 2;
1227c39f472eSBen Skeggs 
1228c39f472eSBen Skeggs 		init_wrvgai(init, 0x03d4, addr, data);
1229c39f472eSBen Skeggs 	}
1230c39f472eSBen Skeggs }
1231c39f472eSBen Skeggs 
1232c39f472eSBen Skeggs /**
1233c39f472eSBen Skeggs  * INIT_CONDITION_TIME - opcode 0x56
1234c39f472eSBen Skeggs  *
1235c39f472eSBen Skeggs  */
1236c39f472eSBen Skeggs static void
init_condition_time(struct nvbios_init * init)1237c39f472eSBen Skeggs init_condition_time(struct nvbios_init *init)
1238c39f472eSBen Skeggs {
12395b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
12407f5f518fSBen Skeggs 	u8  cond = nvbios_rd08(bios, init->offset + 1);
12417f5f518fSBen Skeggs 	u8 retry = nvbios_rd08(bios, init->offset + 2);
1242c39f472eSBen Skeggs 	u8  wait = min((u16)retry * 50, 100);
1243c39f472eSBen Skeggs 
1244c39f472eSBen Skeggs 	trace("CONDITION_TIME\t0x%02x 0x%02x\n", cond, retry);
1245c39f472eSBen Skeggs 	init->offset += 3;
1246c39f472eSBen Skeggs 
1247c39f472eSBen Skeggs 	if (!init_exec(init))
1248c39f472eSBen Skeggs 		return;
1249c39f472eSBen Skeggs 
1250c39f472eSBen Skeggs 	while (wait--) {
1251c39f472eSBen Skeggs 		if (init_condition_met(init, cond))
1252c39f472eSBen Skeggs 			return;
1253c39f472eSBen Skeggs 		mdelay(20);
1254c39f472eSBen Skeggs 	}
1255c39f472eSBen Skeggs 
1256c39f472eSBen Skeggs 	init_exec_set(init, false);
1257c39f472eSBen Skeggs }
1258c39f472eSBen Skeggs 
1259c39f472eSBen Skeggs /**
1260c39f472eSBen Skeggs  * INIT_LTIME - opcode 0x57
1261c39f472eSBen Skeggs  *
1262c39f472eSBen Skeggs  */
1263c39f472eSBen Skeggs static void
init_ltime(struct nvbios_init * init)1264c39f472eSBen Skeggs init_ltime(struct nvbios_init *init)
1265c39f472eSBen Skeggs {
12665b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
12677f5f518fSBen Skeggs 	u16 msec = nvbios_rd16(bios, init->offset + 1);
1268c39f472eSBen Skeggs 
1269c39f472eSBen Skeggs 	trace("LTIME\t0x%04x\n", msec);
1270c39f472eSBen Skeggs 	init->offset += 3;
1271c39f472eSBen Skeggs 
1272c39f472eSBen Skeggs 	if (init_exec(init))
1273c39f472eSBen Skeggs 		mdelay(msec);
1274c39f472eSBen Skeggs }
1275c39f472eSBen Skeggs 
1276c39f472eSBen Skeggs /**
1277c39f472eSBen Skeggs  * INIT_ZM_REG_SEQUENCE - opcode 0x58
1278c39f472eSBen Skeggs  *
1279c39f472eSBen Skeggs  */
1280c39f472eSBen Skeggs static void
init_zm_reg_sequence(struct nvbios_init * init)1281c39f472eSBen Skeggs init_zm_reg_sequence(struct nvbios_init *init)
1282c39f472eSBen Skeggs {
12835b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
12847f5f518fSBen Skeggs 	u32 base = nvbios_rd32(bios, init->offset + 1);
12857f5f518fSBen Skeggs 	u8 count = nvbios_rd08(bios, init->offset + 5);
1286c39f472eSBen Skeggs 
1287c39f472eSBen Skeggs 	trace("ZM_REG_SEQUENCE\t0x%02x\n", count);
1288c39f472eSBen Skeggs 	init->offset += 6;
1289c39f472eSBen Skeggs 
1290c39f472eSBen Skeggs 	while (count--) {
12917f5f518fSBen Skeggs 		u32 data = nvbios_rd32(bios, init->offset);
1292c39f472eSBen Skeggs 
1293c39f472eSBen Skeggs 		trace("\t\tR[0x%06x] = 0x%08x\n", base, data);
1294c39f472eSBen Skeggs 		init->offset += 4;
1295c39f472eSBen Skeggs 
1296c39f472eSBen Skeggs 		init_wr32(init, base, data);
1297c39f472eSBen Skeggs 		base += 4;
1298c39f472eSBen Skeggs 	}
1299c39f472eSBen Skeggs }
1300c39f472eSBen Skeggs 
1301c39f472eSBen Skeggs /**
1302d31b11d8SIlia Mirkin  * INIT_PLL_INDIRECT - opcode 0x59
1303d31b11d8SIlia Mirkin  *
1304d31b11d8SIlia Mirkin  */
1305d31b11d8SIlia Mirkin static void
init_pll_indirect(struct nvbios_init * init)1306d31b11d8SIlia Mirkin init_pll_indirect(struct nvbios_init *init)
1307d31b11d8SIlia Mirkin {
13085b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
13097f5f518fSBen Skeggs 	u32  reg = nvbios_rd32(bios, init->offset + 1);
13107f5f518fSBen Skeggs 	u16 addr = nvbios_rd16(bios, init->offset + 5);
13117f5f518fSBen Skeggs 	u32 freq = (u32)nvbios_rd16(bios, addr) * 1000;
1312d31b11d8SIlia Mirkin 
1313d31b11d8SIlia Mirkin 	trace("PLL_INDIRECT\tR[0x%06x] =PLL= VBIOS[%04x] = %dkHz\n",
1314d31b11d8SIlia Mirkin 	      reg, addr, freq);
1315d31b11d8SIlia Mirkin 	init->offset += 7;
1316d31b11d8SIlia Mirkin 
1317d31b11d8SIlia Mirkin 	init_prog_pll(init, reg, freq);
1318d31b11d8SIlia Mirkin }
1319d31b11d8SIlia Mirkin 
1320d31b11d8SIlia Mirkin /**
1321360ccb84SIlia Mirkin  * INIT_ZM_REG_INDIRECT - opcode 0x5a
1322360ccb84SIlia Mirkin  *
1323360ccb84SIlia Mirkin  */
1324360ccb84SIlia Mirkin static void
init_zm_reg_indirect(struct nvbios_init * init)1325360ccb84SIlia Mirkin init_zm_reg_indirect(struct nvbios_init *init)
1326360ccb84SIlia Mirkin {
13275b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
13287f5f518fSBen Skeggs 	u32  reg = nvbios_rd32(bios, init->offset + 1);
13297f5f518fSBen Skeggs 	u16 addr = nvbios_rd16(bios, init->offset + 5);
13307f5f518fSBen Skeggs 	u32 data = nvbios_rd32(bios, addr);
1331360ccb84SIlia Mirkin 
1332360ccb84SIlia Mirkin 	trace("ZM_REG_INDIRECT\tR[0x%06x] = VBIOS[0x%04x] = 0x%08x\n",
1333360ccb84SIlia Mirkin 	      reg, addr, data);
1334360ccb84SIlia Mirkin 	init->offset += 7;
1335360ccb84SIlia Mirkin 
1336360ccb84SIlia Mirkin 	init_wr32(init, addr, data);
1337360ccb84SIlia Mirkin }
1338360ccb84SIlia Mirkin 
1339360ccb84SIlia Mirkin /**
1340c39f472eSBen Skeggs  * INIT_SUB_DIRECT - opcode 0x5b
1341c39f472eSBen Skeggs  *
1342c39f472eSBen Skeggs  */
1343c39f472eSBen Skeggs static void
init_sub_direct(struct nvbios_init * init)1344c39f472eSBen Skeggs init_sub_direct(struct nvbios_init *init)
1345c39f472eSBen Skeggs {
13465b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
13477f5f518fSBen Skeggs 	u16 addr = nvbios_rd16(bios, init->offset + 1);
1348c39f472eSBen Skeggs 	u16 save;
1349c39f472eSBen Skeggs 
1350c39f472eSBen Skeggs 	trace("SUB_DIRECT\t0x%04x\n", addr);
1351c39f472eSBen Skeggs 
1352c39f472eSBen Skeggs 	if (init_exec(init)) {
1353c39f472eSBen Skeggs 		save = init->offset;
1354c39f472eSBen Skeggs 		init->offset = addr;
1355c39f472eSBen Skeggs 		if (nvbios_exec(init)) {
1356c39f472eSBen Skeggs 			error("error parsing sub-table\n");
1357c39f472eSBen Skeggs 			return;
1358c39f472eSBen Skeggs 		}
1359c39f472eSBen Skeggs 		init->offset = save;
1360c39f472eSBen Skeggs 	}
1361c39f472eSBen Skeggs 
1362c39f472eSBen Skeggs 	init->offset += 3;
1363c39f472eSBen Skeggs }
1364c39f472eSBen Skeggs 
1365c39f472eSBen Skeggs /**
1366c39f472eSBen Skeggs  * INIT_JUMP - opcode 0x5c
1367c39f472eSBen Skeggs  *
1368c39f472eSBen Skeggs  */
1369c39f472eSBen Skeggs static void
init_jump(struct nvbios_init * init)1370c39f472eSBen Skeggs init_jump(struct nvbios_init *init)
1371c39f472eSBen Skeggs {
13725b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
13737f5f518fSBen Skeggs 	u16 offset = nvbios_rd16(bios, init->offset + 1);
1374c39f472eSBen Skeggs 
1375c39f472eSBen Skeggs 	trace("JUMP\t0x%04x\n", offset);
1376c39f472eSBen Skeggs 
1377c39f472eSBen Skeggs 	if (init_exec(init))
1378c39f472eSBen Skeggs 		init->offset = offset;
1379c39f472eSBen Skeggs 	else
1380c39f472eSBen Skeggs 		init->offset += 3;
1381c39f472eSBen Skeggs }
1382c39f472eSBen Skeggs 
1383c39f472eSBen Skeggs /**
1384c39f472eSBen Skeggs  * INIT_I2C_IF - opcode 0x5e
1385c39f472eSBen Skeggs  *
1386c39f472eSBen Skeggs  */
1387c39f472eSBen Skeggs static void
init_i2c_if(struct nvbios_init * init)1388c39f472eSBen Skeggs init_i2c_if(struct nvbios_init *init)
1389c39f472eSBen Skeggs {
13905b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
13917f5f518fSBen Skeggs 	u8 index = nvbios_rd08(bios, init->offset + 1);
13927f5f518fSBen Skeggs 	u8  addr = nvbios_rd08(bios, init->offset + 2);
13937f5f518fSBen Skeggs 	u8   reg = nvbios_rd08(bios, init->offset + 3);
13947f5f518fSBen Skeggs 	u8  mask = nvbios_rd08(bios, init->offset + 4);
13957f5f518fSBen Skeggs 	u8  data = nvbios_rd08(bios, init->offset + 5);
1396c39f472eSBen Skeggs 	u8 value;
1397c39f472eSBen Skeggs 
1398c39f472eSBen Skeggs 	trace("I2C_IF\tI2C[0x%02x][0x%02x][0x%02x] & 0x%02x == 0x%02x\n",
1399c39f472eSBen Skeggs 	      index, addr, reg, mask, data);
1400c39f472eSBen Skeggs 	init->offset += 6;
1401c39f472eSBen Skeggs 	init_exec_force(init, true);
1402c39f472eSBen Skeggs 
1403c39f472eSBen Skeggs 	value = init_rdi2cr(init, index, addr, reg);
1404c39f472eSBen Skeggs 	if ((value & mask) != data)
1405c39f472eSBen Skeggs 		init_exec_set(init, false);
1406c39f472eSBen Skeggs 
1407c39f472eSBen Skeggs 	init_exec_force(init, false);
1408c39f472eSBen Skeggs }
1409c39f472eSBen Skeggs 
1410c39f472eSBen Skeggs /**
1411c39f472eSBen Skeggs  * INIT_COPY_NV_REG - opcode 0x5f
1412c39f472eSBen Skeggs  *
1413c39f472eSBen Skeggs  */
1414c39f472eSBen Skeggs static void
init_copy_nv_reg(struct nvbios_init * init)1415c39f472eSBen Skeggs init_copy_nv_reg(struct nvbios_init *init)
1416c39f472eSBen Skeggs {
14175b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
14187f5f518fSBen Skeggs 	u32  sreg = nvbios_rd32(bios, init->offset + 1);
14197f5f518fSBen Skeggs 	u8  shift = nvbios_rd08(bios, init->offset + 5);
14207f5f518fSBen Skeggs 	u32 smask = nvbios_rd32(bios, init->offset + 6);
14217f5f518fSBen Skeggs 	u32  sxor = nvbios_rd32(bios, init->offset + 10);
14227f5f518fSBen Skeggs 	u32  dreg = nvbios_rd32(bios, init->offset + 14);
14237f5f518fSBen Skeggs 	u32 dmask = nvbios_rd32(bios, init->offset + 18);
1424c39f472eSBen Skeggs 	u32 data;
1425c39f472eSBen Skeggs 
1426c39f472eSBen Skeggs 	trace("COPY_NV_REG\tR[0x%06x] &= 0x%08x |= "
1427c39f472eSBen Skeggs 	      "((R[0x%06x] %s 0x%02x) & 0x%08x ^ 0x%08x)\n",
1428c39f472eSBen Skeggs 	      dreg, dmask, sreg, (shift & 0x80) ? "<<" : ">>",
1429c39f472eSBen Skeggs 	      (shift & 0x80) ? (0x100 - shift) : shift, smask, sxor);
1430c39f472eSBen Skeggs 	init->offset += 22;
1431c39f472eSBen Skeggs 
1432c39f472eSBen Skeggs 	data = init_shift(init_rd32(init, sreg), shift);
1433c39f472eSBen Skeggs 	init_mask(init, dreg, ~dmask, (data & smask) ^ sxor);
1434c39f472eSBen Skeggs }
1435c39f472eSBen Skeggs 
1436c39f472eSBen Skeggs /**
1437c39f472eSBen Skeggs  * INIT_ZM_INDEX_IO - opcode 0x62
1438c39f472eSBen Skeggs  *
1439c39f472eSBen Skeggs  */
1440c39f472eSBen Skeggs static void
init_zm_index_io(struct nvbios_init * init)1441c39f472eSBen Skeggs init_zm_index_io(struct nvbios_init *init)
1442c39f472eSBen Skeggs {
14435b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
14447f5f518fSBen Skeggs 	u16 port = nvbios_rd16(bios, init->offset + 1);
14457f5f518fSBen Skeggs 	u8 index = nvbios_rd08(bios, init->offset + 3);
14467f5f518fSBen Skeggs 	u8  data = nvbios_rd08(bios, init->offset + 4);
1447c39f472eSBen Skeggs 
1448c39f472eSBen Skeggs 	trace("ZM_INDEX_IO\tI[0x%04x][0x%02x] = 0x%02x\n", port, index, data);
1449c39f472eSBen Skeggs 	init->offset += 5;
1450c39f472eSBen Skeggs 
1451c39f472eSBen Skeggs 	init_wrvgai(init, port, index, data);
1452c39f472eSBen Skeggs }
1453c39f472eSBen Skeggs 
1454c39f472eSBen Skeggs /**
1455c39f472eSBen Skeggs  * INIT_COMPUTE_MEM - opcode 0x63
1456c39f472eSBen Skeggs  *
1457c39f472eSBen Skeggs  */
1458c39f472eSBen Skeggs static void
init_compute_mem(struct nvbios_init * init)1459c39f472eSBen Skeggs init_compute_mem(struct nvbios_init *init)
1460c39f472eSBen Skeggs {
14615b0e787aSBen Skeggs 	struct nvkm_devinit *devinit = init->subdev->device->devinit;
1462c39f472eSBen Skeggs 
1463c39f472eSBen Skeggs 	trace("COMPUTE_MEM\n");
1464c39f472eSBen Skeggs 	init->offset += 1;
1465c39f472eSBen Skeggs 
1466c39f472eSBen Skeggs 	init_exec_force(init, true);
1467151abd44SBen Skeggs 	if (init_exec(init))
1468151abd44SBen Skeggs 		nvkm_devinit_meminit(devinit);
1469c39f472eSBen Skeggs 	init_exec_force(init, false);
1470c39f472eSBen Skeggs }
1471c39f472eSBen Skeggs 
1472c39f472eSBen Skeggs /**
1473c39f472eSBen Skeggs  * INIT_RESET - opcode 0x65
1474c39f472eSBen Skeggs  *
1475c39f472eSBen Skeggs  */
1476c39f472eSBen Skeggs static void
init_reset(struct nvbios_init * init)1477c39f472eSBen Skeggs init_reset(struct nvbios_init *init)
1478c39f472eSBen Skeggs {
14795b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
14807f5f518fSBen Skeggs 	u32   reg = nvbios_rd32(bios, init->offset + 1);
14817f5f518fSBen Skeggs 	u32 data1 = nvbios_rd32(bios, init->offset + 5);
14827f5f518fSBen Skeggs 	u32 data2 = nvbios_rd32(bios, init->offset + 9);
1483c39f472eSBen Skeggs 	u32 savepci19;
1484c39f472eSBen Skeggs 
1485c39f472eSBen Skeggs 	trace("RESET\tR[0x%08x] = 0x%08x, 0x%08x", reg, data1, data2);
1486c39f472eSBen Skeggs 	init->offset += 13;
1487c39f472eSBen Skeggs 	init_exec_force(init, true);
1488c39f472eSBen Skeggs 
1489c39f472eSBen Skeggs 	savepci19 = init_mask(init, 0x00184c, 0x00000f00, 0x00000000);
1490c39f472eSBen Skeggs 	init_wr32(init, reg, data1);
1491c39f472eSBen Skeggs 	udelay(10);
1492c39f472eSBen Skeggs 	init_wr32(init, reg, data2);
1493c39f472eSBen Skeggs 	init_wr32(init, 0x00184c, savepci19);
1494c39f472eSBen Skeggs 	init_mask(init, 0x001850, 0x00000001, 0x00000000);
1495c39f472eSBen Skeggs 
1496c39f472eSBen Skeggs 	init_exec_force(init, false);
1497c39f472eSBen Skeggs }
1498c39f472eSBen Skeggs 
1499c39f472eSBen Skeggs /**
1500c39f472eSBen Skeggs  * INIT_CONFIGURE_MEM - opcode 0x66
1501c39f472eSBen Skeggs  *
1502c39f472eSBen Skeggs  */
1503c39f472eSBen Skeggs static u16
init_configure_mem_clk(struct nvbios_init * init)1504c39f472eSBen Skeggs init_configure_mem_clk(struct nvbios_init *init)
1505c39f472eSBen Skeggs {
15065b0e787aSBen Skeggs 	u16 mdata = bmp_mem_init_table(init->subdev->device->bios);
1507c39f472eSBen Skeggs 	if (mdata)
1508c39f472eSBen Skeggs 		mdata += (init_rdvgai(init, 0x03d4, 0x3c) >> 4) * 66;
1509c39f472eSBen Skeggs 	return mdata;
1510c39f472eSBen Skeggs }
1511c39f472eSBen Skeggs 
1512c39f472eSBen Skeggs static void
init_configure_mem(struct nvbios_init * init)1513c39f472eSBen Skeggs init_configure_mem(struct nvbios_init *init)
1514c39f472eSBen Skeggs {
15155b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
1516c39f472eSBen Skeggs 	u16 mdata, sdata;
1517c39f472eSBen Skeggs 	u32 addr, data;
1518c39f472eSBen Skeggs 
1519c39f472eSBen Skeggs 	trace("CONFIGURE_MEM\n");
1520c39f472eSBen Skeggs 	init->offset += 1;
1521c39f472eSBen Skeggs 
1522c39f472eSBen Skeggs 	if (bios->version.major > 2) {
1523c39f472eSBen Skeggs 		init_done(init);
1524c39f472eSBen Skeggs 		return;
1525c39f472eSBen Skeggs 	}
1526c39f472eSBen Skeggs 	init_exec_force(init, true);
1527c39f472eSBen Skeggs 
1528c39f472eSBen Skeggs 	mdata = init_configure_mem_clk(init);
1529c39f472eSBen Skeggs 	sdata = bmp_sdr_seq_table(bios);
15307f5f518fSBen Skeggs 	if (nvbios_rd08(bios, mdata) & 0x01)
1531c39f472eSBen Skeggs 		sdata = bmp_ddr_seq_table(bios);
1532c39f472eSBen Skeggs 	mdata += 6; /* skip to data */
1533c39f472eSBen Skeggs 
1534c39f472eSBen Skeggs 	data = init_rdvgai(init, 0x03c4, 0x01);
1535c39f472eSBen Skeggs 	init_wrvgai(init, 0x03c4, 0x01, data | 0x20);
1536c39f472eSBen Skeggs 
15377f5f518fSBen Skeggs 	for (; (addr = nvbios_rd32(bios, sdata)) != 0xffffffff; sdata += 4) {
1538c39f472eSBen Skeggs 		switch (addr) {
1539c39f472eSBen Skeggs 		case 0x10021c: /* CKE_NORMAL */
1540c39f472eSBen Skeggs 		case 0x1002d0: /* CMD_REFRESH */
1541c39f472eSBen Skeggs 		case 0x1002d4: /* CMD_PRECHARGE */
1542c39f472eSBen Skeggs 			data = 0x00000001;
1543c39f472eSBen Skeggs 			break;
1544c39f472eSBen Skeggs 		default:
15457f5f518fSBen Skeggs 			data = nvbios_rd32(bios, mdata);
1546c39f472eSBen Skeggs 			mdata += 4;
1547c39f472eSBen Skeggs 			if (data == 0xffffffff)
1548c39f472eSBen Skeggs 				continue;
1549c39f472eSBen Skeggs 			break;
1550c39f472eSBen Skeggs 		}
1551c39f472eSBen Skeggs 
1552c39f472eSBen Skeggs 		init_wr32(init, addr, data);
1553c39f472eSBen Skeggs 	}
1554c39f472eSBen Skeggs 
1555c39f472eSBen Skeggs 	init_exec_force(init, false);
1556c39f472eSBen Skeggs }
1557c39f472eSBen Skeggs 
1558c39f472eSBen Skeggs /**
1559c39f472eSBen Skeggs  * INIT_CONFIGURE_CLK - opcode 0x67
1560c39f472eSBen Skeggs  *
1561c39f472eSBen Skeggs  */
1562c39f472eSBen Skeggs static void
init_configure_clk(struct nvbios_init * init)1563c39f472eSBen Skeggs init_configure_clk(struct nvbios_init *init)
1564c39f472eSBen Skeggs {
15655b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
1566c39f472eSBen Skeggs 	u16 mdata, clock;
1567c39f472eSBen Skeggs 
1568c39f472eSBen Skeggs 	trace("CONFIGURE_CLK\n");
1569c39f472eSBen Skeggs 	init->offset += 1;
1570c39f472eSBen Skeggs 
1571c39f472eSBen Skeggs 	if (bios->version.major > 2) {
1572c39f472eSBen Skeggs 		init_done(init);
1573c39f472eSBen Skeggs 		return;
1574c39f472eSBen Skeggs 	}
1575c39f472eSBen Skeggs 	init_exec_force(init, true);
1576c39f472eSBen Skeggs 
1577c39f472eSBen Skeggs 	mdata = init_configure_mem_clk(init);
1578c39f472eSBen Skeggs 
1579c39f472eSBen Skeggs 	/* NVPLL */
15807f5f518fSBen Skeggs 	clock = nvbios_rd16(bios, mdata + 4) * 10;
1581c39f472eSBen Skeggs 	init_prog_pll(init, 0x680500, clock);
1582c39f472eSBen Skeggs 
1583c39f472eSBen Skeggs 	/* MPLL */
15847f5f518fSBen Skeggs 	clock = nvbios_rd16(bios, mdata + 2) * 10;
15857f5f518fSBen Skeggs 	if (nvbios_rd08(bios, mdata) & 0x01)
1586c39f472eSBen Skeggs 		clock *= 2;
1587c39f472eSBen Skeggs 	init_prog_pll(init, 0x680504, clock);
1588c39f472eSBen Skeggs 
1589c39f472eSBen Skeggs 	init_exec_force(init, false);
1590c39f472eSBen Skeggs }
1591c39f472eSBen Skeggs 
1592c39f472eSBen Skeggs /**
1593c39f472eSBen Skeggs  * INIT_CONFIGURE_PREINIT - opcode 0x68
1594c39f472eSBen Skeggs  *
1595c39f472eSBen Skeggs  */
1596c39f472eSBen Skeggs static void
init_configure_preinit(struct nvbios_init * init)1597c39f472eSBen Skeggs init_configure_preinit(struct nvbios_init *init)
1598c39f472eSBen Skeggs {
15995b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
1600c39f472eSBen Skeggs 	u32 strap;
1601c39f472eSBen Skeggs 
1602c39f472eSBen Skeggs 	trace("CONFIGURE_PREINIT\n");
1603c39f472eSBen Skeggs 	init->offset += 1;
1604c39f472eSBen Skeggs 
1605c39f472eSBen Skeggs 	if (bios->version.major > 2) {
1606c39f472eSBen Skeggs 		init_done(init);
1607c39f472eSBen Skeggs 		return;
1608c39f472eSBen Skeggs 	}
1609c39f472eSBen Skeggs 	init_exec_force(init, true);
1610c39f472eSBen Skeggs 
1611c39f472eSBen Skeggs 	strap = init_rd32(init, 0x101000);
1612c39f472eSBen Skeggs 	strap = ((strap << 2) & 0xf0) | ((strap & 0x40) >> 6);
1613c39f472eSBen Skeggs 	init_wrvgai(init, 0x03d4, 0x3c, strap);
1614c39f472eSBen Skeggs 
1615c39f472eSBen Skeggs 	init_exec_force(init, false);
1616c39f472eSBen Skeggs }
1617c39f472eSBen Skeggs 
1618c39f472eSBen Skeggs /**
1619c39f472eSBen Skeggs  * INIT_IO - opcode 0x69
1620c39f472eSBen Skeggs  *
1621c39f472eSBen Skeggs  */
1622c39f472eSBen Skeggs static void
init_io(struct nvbios_init * init)1623c39f472eSBen Skeggs init_io(struct nvbios_init *init)
1624c39f472eSBen Skeggs {
16255b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
16267f5f518fSBen Skeggs 	u16 port = nvbios_rd16(bios, init->offset + 1);
16277f5f518fSBen Skeggs 	u8  mask = nvbios_rd16(bios, init->offset + 3);
16287f5f518fSBen Skeggs 	u8  data = nvbios_rd16(bios, init->offset + 4);
1629c39f472eSBen Skeggs 	u8 value;
1630c39f472eSBen Skeggs 
1631c39f472eSBen Skeggs 	trace("IO\t\tI[0x%04x] &= 0x%02x |= 0x%02x\n", port, mask, data);
1632c39f472eSBen Skeggs 	init->offset += 5;
1633c39f472eSBen Skeggs 
1634c39f472eSBen Skeggs 	/* ummm.. yes.. should really figure out wtf this is and why it's
1635c39f472eSBen Skeggs 	 * needed some day..  it's almost certainly wrong, but, it also
1636c39f472eSBen Skeggs 	 * somehow makes things work...
1637c39f472eSBen Skeggs 	 */
163846484438SBen Skeggs 	if (bios->subdev.device->card_type >= NV_50 &&
1639c39f472eSBen Skeggs 	    port == 0x03c3 && data == 0x01) {
1640c39f472eSBen Skeggs 		init_mask(init, 0x614100, 0xf0800000, 0x00800000);
1641c39f472eSBen Skeggs 		init_mask(init, 0x00e18c, 0x00020000, 0x00020000);
1642c39f472eSBen Skeggs 		init_mask(init, 0x614900, 0xf0800000, 0x00800000);
1643c39f472eSBen Skeggs 		init_mask(init, 0x000200, 0x40000000, 0x00000000);
1644c39f472eSBen Skeggs 		mdelay(10);
1645c39f472eSBen Skeggs 		init_mask(init, 0x00e18c, 0x00020000, 0x00000000);
1646c39f472eSBen Skeggs 		init_mask(init, 0x000200, 0x40000000, 0x40000000);
1647c39f472eSBen Skeggs 		init_wr32(init, 0x614100, 0x00800018);
1648c39f472eSBen Skeggs 		init_wr32(init, 0x614900, 0x00800018);
1649c39f472eSBen Skeggs 		mdelay(10);
1650c39f472eSBen Skeggs 		init_wr32(init, 0x614100, 0x10000018);
1651c39f472eSBen Skeggs 		init_wr32(init, 0x614900, 0x10000018);
1652c39f472eSBen Skeggs 	}
1653c39f472eSBen Skeggs 
1654c39f472eSBen Skeggs 	value = init_rdport(init, port) & mask;
1655c39f472eSBen Skeggs 	init_wrport(init, port, data | value);
1656c39f472eSBen Skeggs }
1657c39f472eSBen Skeggs 
1658c39f472eSBen Skeggs /**
1659c39f472eSBen Skeggs  * INIT_SUB - opcode 0x6b
1660c39f472eSBen Skeggs  *
1661c39f472eSBen Skeggs  */
1662c39f472eSBen Skeggs static void
init_sub(struct nvbios_init * init)1663c39f472eSBen Skeggs init_sub(struct nvbios_init *init)
1664c39f472eSBen Skeggs {
16655b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
16667f5f518fSBen Skeggs 	u8 index = nvbios_rd08(bios, init->offset + 1);
1667c39f472eSBen Skeggs 	u16 addr, save;
1668c39f472eSBen Skeggs 
1669c39f472eSBen Skeggs 	trace("SUB\t0x%02x\n", index);
1670c39f472eSBen Skeggs 
1671c39f472eSBen Skeggs 	addr = init_script(bios, index);
1672c39f472eSBen Skeggs 	if (addr && init_exec(init)) {
1673c39f472eSBen Skeggs 		save = init->offset;
1674c39f472eSBen Skeggs 		init->offset = addr;
1675c39f472eSBen Skeggs 		if (nvbios_exec(init)) {
1676c39f472eSBen Skeggs 			error("error parsing sub-table\n");
1677c39f472eSBen Skeggs 			return;
1678c39f472eSBen Skeggs 		}
1679c39f472eSBen Skeggs 		init->offset = save;
1680c39f472eSBen Skeggs 	}
1681c39f472eSBen Skeggs 
1682c39f472eSBen Skeggs 	init->offset += 2;
1683c39f472eSBen Skeggs }
1684c39f472eSBen Skeggs 
1685c39f472eSBen Skeggs /**
1686c39f472eSBen Skeggs  * INIT_RAM_CONDITION - opcode 0x6d
1687c39f472eSBen Skeggs  *
1688c39f472eSBen Skeggs  */
1689c39f472eSBen Skeggs static void
init_ram_condition(struct nvbios_init * init)1690c39f472eSBen Skeggs init_ram_condition(struct nvbios_init *init)
1691c39f472eSBen Skeggs {
16925b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
16937f5f518fSBen Skeggs 	u8  mask = nvbios_rd08(bios, init->offset + 1);
16947f5f518fSBen Skeggs 	u8 value = nvbios_rd08(bios, init->offset + 2);
1695c39f472eSBen Skeggs 
1696c39f472eSBen Skeggs 	trace("RAM_CONDITION\t"
1697c39f472eSBen Skeggs 	      "(R[0x100000] & 0x%02x) == 0x%02x\n", mask, value);
1698c39f472eSBen Skeggs 	init->offset += 3;
1699c39f472eSBen Skeggs 
1700c39f472eSBen Skeggs 	if ((init_rd32(init, 0x100000) & mask) != value)
1701c39f472eSBen Skeggs 		init_exec_set(init, false);
1702c39f472eSBen Skeggs }
1703c39f472eSBen Skeggs 
1704c39f472eSBen Skeggs /**
1705c39f472eSBen Skeggs  * INIT_NV_REG - opcode 0x6e
1706c39f472eSBen Skeggs  *
1707c39f472eSBen Skeggs  */
1708c39f472eSBen Skeggs static void
init_nv_reg(struct nvbios_init * init)1709c39f472eSBen Skeggs init_nv_reg(struct nvbios_init *init)
1710c39f472eSBen Skeggs {
17115b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
17127f5f518fSBen Skeggs 	u32  reg = nvbios_rd32(bios, init->offset + 1);
17137f5f518fSBen Skeggs 	u32 mask = nvbios_rd32(bios, init->offset + 5);
17147f5f518fSBen Skeggs 	u32 data = nvbios_rd32(bios, init->offset + 9);
1715c39f472eSBen Skeggs 
1716c39f472eSBen Skeggs 	trace("NV_REG\tR[0x%06x] &= 0x%08x |= 0x%08x\n", reg, mask, data);
1717c39f472eSBen Skeggs 	init->offset += 13;
1718c39f472eSBen Skeggs 
1719c39f472eSBen Skeggs 	init_mask(init, reg, ~mask, data);
1720c39f472eSBen Skeggs }
1721c39f472eSBen Skeggs 
1722c39f472eSBen Skeggs /**
1723c39f472eSBen Skeggs  * INIT_MACRO - opcode 0x6f
1724c39f472eSBen Skeggs  *
1725c39f472eSBen Skeggs  */
1726c39f472eSBen Skeggs static void
init_macro(struct nvbios_init * init)1727c39f472eSBen Skeggs init_macro(struct nvbios_init *init)
1728c39f472eSBen Skeggs {
17295b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
17307f5f518fSBen Skeggs 	u8  macro = nvbios_rd08(bios, init->offset + 1);
1731c39f472eSBen Skeggs 	u16 table;
1732c39f472eSBen Skeggs 
1733c39f472eSBen Skeggs 	trace("MACRO\t0x%02x\n", macro);
1734c39f472eSBen Skeggs 
1735c39f472eSBen Skeggs 	table = init_macro_table(init);
1736c39f472eSBen Skeggs 	if (table) {
17377f5f518fSBen Skeggs 		u32 addr = nvbios_rd32(bios, table + (macro * 8) + 0);
17387f5f518fSBen Skeggs 		u32 data = nvbios_rd32(bios, table + (macro * 8) + 4);
1739c39f472eSBen Skeggs 		trace("\t\tR[0x%06x] = 0x%08x\n", addr, data);
1740c39f472eSBen Skeggs 		init_wr32(init, addr, data);
1741c39f472eSBen Skeggs 	}
1742c39f472eSBen Skeggs 
1743c39f472eSBen Skeggs 	init->offset += 2;
1744c39f472eSBen Skeggs }
1745c39f472eSBen Skeggs 
1746c39f472eSBen Skeggs /**
1747c39f472eSBen Skeggs  * INIT_RESUME - opcode 0x72
1748c39f472eSBen Skeggs  *
1749c39f472eSBen Skeggs  */
1750c39f472eSBen Skeggs static void
init_resume(struct nvbios_init * init)1751c39f472eSBen Skeggs init_resume(struct nvbios_init *init)
1752c39f472eSBen Skeggs {
1753c39f472eSBen Skeggs 	trace("RESUME\n");
1754c39f472eSBen Skeggs 	init->offset += 1;
1755c39f472eSBen Skeggs 	init_exec_set(init, true);
1756c39f472eSBen Skeggs }
1757c39f472eSBen Skeggs 
1758c39f472eSBen Skeggs /**
1759bacbad17SIlia Mirkin  * INIT_STRAP_CONDITION - opcode 0x73
1760bacbad17SIlia Mirkin  *
1761bacbad17SIlia Mirkin  */
1762bacbad17SIlia Mirkin static void
init_strap_condition(struct nvbios_init * init)1763bacbad17SIlia Mirkin init_strap_condition(struct nvbios_init *init)
1764bacbad17SIlia Mirkin {
17655b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
17667f5f518fSBen Skeggs 	u32 mask = nvbios_rd32(bios, init->offset + 1);
17677f5f518fSBen Skeggs 	u32 value = nvbios_rd32(bios, init->offset + 5);
1768bacbad17SIlia Mirkin 
1769bacbad17SIlia Mirkin 	trace("STRAP_CONDITION\t(R[0x101000] & 0x%08x) == 0x%08x\n", mask, value);
1770bacbad17SIlia Mirkin 	init->offset += 9;
1771bacbad17SIlia Mirkin 
1772bacbad17SIlia Mirkin 	if ((init_rd32(init, 0x101000) & mask) != value)
1773bacbad17SIlia Mirkin 		init_exec_set(init, false);
1774bacbad17SIlia Mirkin }
1775bacbad17SIlia Mirkin 
1776bacbad17SIlia Mirkin /**
1777c39f472eSBen Skeggs  * INIT_TIME - opcode 0x74
1778c39f472eSBen Skeggs  *
1779c39f472eSBen Skeggs  */
1780c39f472eSBen Skeggs static void
init_time(struct nvbios_init * init)1781c39f472eSBen Skeggs init_time(struct nvbios_init *init)
1782c39f472eSBen Skeggs {
17835b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
17847f5f518fSBen Skeggs 	u16 usec = nvbios_rd16(bios, init->offset + 1);
1785c39f472eSBen Skeggs 
1786c39f472eSBen Skeggs 	trace("TIME\t0x%04x\n", usec);
1787c39f472eSBen Skeggs 	init->offset += 3;
1788c39f472eSBen Skeggs 
1789c39f472eSBen Skeggs 	if (init_exec(init)) {
1790c39f472eSBen Skeggs 		if (usec < 1000)
1791c39f472eSBen Skeggs 			udelay(usec);
1792c39f472eSBen Skeggs 		else
1793c39f472eSBen Skeggs 			mdelay((usec + 900) / 1000);
1794c39f472eSBen Skeggs 	}
1795c39f472eSBen Skeggs }
1796c39f472eSBen Skeggs 
1797c39f472eSBen Skeggs /**
1798c39f472eSBen Skeggs  * INIT_CONDITION - opcode 0x75
1799c39f472eSBen Skeggs  *
1800c39f472eSBen Skeggs  */
1801c39f472eSBen Skeggs static void
init_condition(struct nvbios_init * init)1802c39f472eSBen Skeggs init_condition(struct nvbios_init *init)
1803c39f472eSBen Skeggs {
18045b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
18057f5f518fSBen Skeggs 	u8 cond = nvbios_rd08(bios, init->offset + 1);
1806c39f472eSBen Skeggs 
1807c39f472eSBen Skeggs 	trace("CONDITION\t0x%02x\n", cond);
1808c39f472eSBen Skeggs 	init->offset += 2;
1809c39f472eSBen Skeggs 
1810c39f472eSBen Skeggs 	if (!init_condition_met(init, cond))
1811c39f472eSBen Skeggs 		init_exec_set(init, false);
1812c39f472eSBen Skeggs }
1813c39f472eSBen Skeggs 
1814c39f472eSBen Skeggs /**
1815c39f472eSBen Skeggs  * INIT_IO_CONDITION - opcode 0x76
1816c39f472eSBen Skeggs  *
1817c39f472eSBen Skeggs  */
1818c39f472eSBen Skeggs static void
init_io_condition(struct nvbios_init * init)1819c39f472eSBen Skeggs init_io_condition(struct nvbios_init *init)
1820c39f472eSBen Skeggs {
18215b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
18227f5f518fSBen Skeggs 	u8 cond = nvbios_rd08(bios, init->offset + 1);
1823c39f472eSBen Skeggs 
1824c39f472eSBen Skeggs 	trace("IO_CONDITION\t0x%02x\n", cond);
1825c39f472eSBen Skeggs 	init->offset += 2;
1826c39f472eSBen Skeggs 
1827c39f472eSBen Skeggs 	if (!init_io_condition_met(init, cond))
1828c39f472eSBen Skeggs 		init_exec_set(init, false);
1829c39f472eSBen Skeggs }
1830c39f472eSBen Skeggs 
1831c39f472eSBen Skeggs /**
1832bacbad17SIlia Mirkin  * INIT_ZM_REG16 - opcode 0x77
1833bacbad17SIlia Mirkin  *
1834bacbad17SIlia Mirkin  */
1835bacbad17SIlia Mirkin static void
init_zm_reg16(struct nvbios_init * init)1836bacbad17SIlia Mirkin init_zm_reg16(struct nvbios_init *init)
1837bacbad17SIlia Mirkin {
18385b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
18397f5f518fSBen Skeggs 	u32 addr = nvbios_rd32(bios, init->offset + 1);
18407f5f518fSBen Skeggs 	u16 data = nvbios_rd16(bios, init->offset + 5);
1841bacbad17SIlia Mirkin 
1842bacbad17SIlia Mirkin 	trace("ZM_REG\tR[0x%06x] = 0x%04x\n", addr, data);
1843bacbad17SIlia Mirkin 	init->offset += 7;
1844bacbad17SIlia Mirkin 
1845bacbad17SIlia Mirkin 	init_wr32(init, addr, data);
1846bacbad17SIlia Mirkin }
1847bacbad17SIlia Mirkin 
1848bacbad17SIlia Mirkin /**
1849c39f472eSBen Skeggs  * INIT_INDEX_IO - opcode 0x78
1850c39f472eSBen Skeggs  *
1851c39f472eSBen Skeggs  */
1852c39f472eSBen Skeggs static void
init_index_io(struct nvbios_init * init)1853c39f472eSBen Skeggs init_index_io(struct nvbios_init *init)
1854c39f472eSBen Skeggs {
18555b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
18567f5f518fSBen Skeggs 	u16 port = nvbios_rd16(bios, init->offset + 1);
18577f5f518fSBen Skeggs 	u8 index = nvbios_rd16(bios, init->offset + 3);
18587f5f518fSBen Skeggs 	u8  mask = nvbios_rd08(bios, init->offset + 4);
18597f5f518fSBen Skeggs 	u8  data = nvbios_rd08(bios, init->offset + 5);
1860c39f472eSBen Skeggs 	u8 value;
1861c39f472eSBen Skeggs 
1862c39f472eSBen Skeggs 	trace("INDEX_IO\tI[0x%04x][0x%02x] &= 0x%02x |= 0x%02x\n",
1863c39f472eSBen Skeggs 	      port, index, mask, data);
1864c39f472eSBen Skeggs 	init->offset += 6;
1865c39f472eSBen Skeggs 
1866c39f472eSBen Skeggs 	value = init_rdvgai(init, port, index) & mask;
1867c39f472eSBen Skeggs 	init_wrvgai(init, port, index, data | value);
1868c39f472eSBen Skeggs }
1869c39f472eSBen Skeggs 
1870c39f472eSBen Skeggs /**
1871c39f472eSBen Skeggs  * INIT_PLL - opcode 0x79
1872c39f472eSBen Skeggs  *
1873c39f472eSBen Skeggs  */
1874c39f472eSBen Skeggs static void
init_pll(struct nvbios_init * init)1875c39f472eSBen Skeggs init_pll(struct nvbios_init *init)
1876c39f472eSBen Skeggs {
18775b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
18787f5f518fSBen Skeggs 	u32  reg = nvbios_rd32(bios, init->offset + 1);
18797f5f518fSBen Skeggs 	u32 freq = nvbios_rd16(bios, init->offset + 5) * 10;
1880c39f472eSBen Skeggs 
1881c39f472eSBen Skeggs 	trace("PLL\tR[0x%06x] =PLL= %dkHz\n", reg, freq);
1882c39f472eSBen Skeggs 	init->offset += 7;
1883c39f472eSBen Skeggs 
1884c39f472eSBen Skeggs 	init_prog_pll(init, reg, freq);
1885c39f472eSBen Skeggs }
1886c39f472eSBen Skeggs 
1887c39f472eSBen Skeggs /**
1888c39f472eSBen Skeggs  * INIT_ZM_REG - opcode 0x7a
1889c39f472eSBen Skeggs  *
1890c39f472eSBen Skeggs  */
1891c39f472eSBen Skeggs static void
init_zm_reg(struct nvbios_init * init)1892c39f472eSBen Skeggs init_zm_reg(struct nvbios_init *init)
1893c39f472eSBen Skeggs {
18945b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
18957f5f518fSBen Skeggs 	u32 addr = nvbios_rd32(bios, init->offset + 1);
18967f5f518fSBen Skeggs 	u32 data = nvbios_rd32(bios, init->offset + 5);
1897c39f472eSBen Skeggs 
1898c39f472eSBen Skeggs 	trace("ZM_REG\tR[0x%06x] = 0x%08x\n", addr, data);
1899c39f472eSBen Skeggs 	init->offset += 9;
1900c39f472eSBen Skeggs 
1901c39f472eSBen Skeggs 	if (addr == 0x000200)
1902c39f472eSBen Skeggs 		data |= 0x00000001;
1903c39f472eSBen Skeggs 
1904c39f472eSBen Skeggs 	init_wr32(init, addr, data);
1905c39f472eSBen Skeggs }
1906c39f472eSBen Skeggs 
1907c39f472eSBen Skeggs /**
1908c39f472eSBen Skeggs  * INIT_RAM_RESTRICT_PLL - opcde 0x87
1909c39f472eSBen Skeggs  *
1910c39f472eSBen Skeggs  */
1911c39f472eSBen Skeggs static void
init_ram_restrict_pll(struct nvbios_init * init)1912c39f472eSBen Skeggs init_ram_restrict_pll(struct nvbios_init *init)
1913c39f472eSBen Skeggs {
19145b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
19157f5f518fSBen Skeggs 	u8  type = nvbios_rd08(bios, init->offset + 1);
1916c39f472eSBen Skeggs 	u8 count = init_ram_restrict_group_count(init);
1917c39f472eSBen Skeggs 	u8 strap = init_ram_restrict(init);
1918c39f472eSBen Skeggs 	u8 cconf;
1919c39f472eSBen Skeggs 
1920c39f472eSBen Skeggs 	trace("RAM_RESTRICT_PLL\t0x%02x\n", type);
1921c39f472eSBen Skeggs 	init->offset += 2;
1922c39f472eSBen Skeggs 
1923c39f472eSBen Skeggs 	for (cconf = 0; cconf < count; cconf++) {
19247f5f518fSBen Skeggs 		u32 freq = nvbios_rd32(bios, init->offset);
1925c39f472eSBen Skeggs 
1926c39f472eSBen Skeggs 		if (cconf == strap) {
1927c39f472eSBen Skeggs 			trace("%dkHz *\n", freq);
1928c39f472eSBen Skeggs 			init_prog_pll(init, type, freq);
1929c39f472eSBen Skeggs 		} else {
1930c39f472eSBen Skeggs 			trace("%dkHz\n", freq);
1931c39f472eSBen Skeggs 		}
1932c39f472eSBen Skeggs 
1933c39f472eSBen Skeggs 		init->offset += 4;
1934c39f472eSBen Skeggs 	}
1935c39f472eSBen Skeggs }
1936c39f472eSBen Skeggs 
1937c39f472eSBen Skeggs /**
193866cbcc72SRhys Kidd  * INIT_RESET_BEGUN - opcode 0x8c
193966cbcc72SRhys Kidd  *
194066cbcc72SRhys Kidd  */
194166cbcc72SRhys Kidd static void
init_reset_begun(struct nvbios_init * init)194266cbcc72SRhys Kidd init_reset_begun(struct nvbios_init *init)
194366cbcc72SRhys Kidd {
194466cbcc72SRhys Kidd 	trace("RESET_BEGUN\n");
194566cbcc72SRhys Kidd 	init->offset += 1;
194666cbcc72SRhys Kidd }
194766cbcc72SRhys Kidd 
194866cbcc72SRhys Kidd /**
19499f9b4507SRhys Kidd  * INIT_RESET_END - opcode 0x8d
19509f9b4507SRhys Kidd  *
19519f9b4507SRhys Kidd  */
19529f9b4507SRhys Kidd static void
init_reset_end(struct nvbios_init * init)19539f9b4507SRhys Kidd init_reset_end(struct nvbios_init *init)
19549f9b4507SRhys Kidd {
19559f9b4507SRhys Kidd 	trace("RESET_END\n");
19569f9b4507SRhys Kidd 	init->offset += 1;
19579f9b4507SRhys Kidd }
19589f9b4507SRhys Kidd 
19599f9b4507SRhys Kidd /**
1960c39f472eSBen Skeggs  * INIT_GPIO - opcode 0x8e
1961c39f472eSBen Skeggs  *
1962c39f472eSBen Skeggs  */
1963c39f472eSBen Skeggs static void
init_gpio(struct nvbios_init * init)1964c39f472eSBen Skeggs init_gpio(struct nvbios_init *init)
1965c39f472eSBen Skeggs {
19665b0e787aSBen Skeggs 	struct nvkm_gpio *gpio = init->subdev->device->gpio;
1967c39f472eSBen Skeggs 
1968c39f472eSBen Skeggs 	trace("GPIO\n");
1969c39f472eSBen Skeggs 	init->offset += 1;
1970c39f472eSBen Skeggs 
19712ea7249fSBen Skeggs 	if (init_exec(init))
19722ea7249fSBen Skeggs 		nvkm_gpio_reset(gpio, DCB_GPIO_UNUSED);
1973c39f472eSBen Skeggs }
1974c39f472eSBen Skeggs 
1975c39f472eSBen Skeggs /**
1976c39f472eSBen Skeggs  * INIT_RAM_RESTRICT_ZM_GROUP - opcode 0x8f
1977c39f472eSBen Skeggs  *
1978c39f472eSBen Skeggs  */
1979c39f472eSBen Skeggs static void
init_ram_restrict_zm_reg_group(struct nvbios_init * init)1980c39f472eSBen Skeggs init_ram_restrict_zm_reg_group(struct nvbios_init *init)
1981c39f472eSBen Skeggs {
19825b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
19837f5f518fSBen Skeggs 	u32 addr = nvbios_rd32(bios, init->offset + 1);
19847f5f518fSBen Skeggs 	u8  incr = nvbios_rd08(bios, init->offset + 5);
19857f5f518fSBen Skeggs 	u8   num = nvbios_rd08(bios, init->offset + 6);
1986c39f472eSBen Skeggs 	u8 count = init_ram_restrict_group_count(init);
1987c39f472eSBen Skeggs 	u8 index = init_ram_restrict(init);
1988c39f472eSBen Skeggs 	u8 i, j;
1989c39f472eSBen Skeggs 
1990c39f472eSBen Skeggs 	trace("RAM_RESTRICT_ZM_REG_GROUP\t"
1991c39f472eSBen Skeggs 	      "R[0x%08x] 0x%02x 0x%02x\n", addr, incr, num);
1992c39f472eSBen Skeggs 	init->offset += 7;
1993c39f472eSBen Skeggs 
1994c39f472eSBen Skeggs 	for (i = 0; i < num; i++) {
1995c39f472eSBen Skeggs 		trace("\tR[0x%06x] = {\n", addr);
1996c39f472eSBen Skeggs 		for (j = 0; j < count; j++) {
19977f5f518fSBen Skeggs 			u32 data = nvbios_rd32(bios, init->offset);
1998c39f472eSBen Skeggs 
1999c39f472eSBen Skeggs 			if (j == index) {
2000c39f472eSBen Skeggs 				trace("\t\t0x%08x *\n", data);
2001c39f472eSBen Skeggs 				init_wr32(init, addr, data);
2002c39f472eSBen Skeggs 			} else {
2003c39f472eSBen Skeggs 				trace("\t\t0x%08x\n", data);
2004c39f472eSBen Skeggs 			}
2005c39f472eSBen Skeggs 
2006c39f472eSBen Skeggs 			init->offset += 4;
2007c39f472eSBen Skeggs 		}
2008c39f472eSBen Skeggs 		trace("\t}\n");
2009c39f472eSBen Skeggs 		addr += incr;
2010c39f472eSBen Skeggs 	}
2011c39f472eSBen Skeggs }
2012c39f472eSBen Skeggs 
2013c39f472eSBen Skeggs /**
2014c39f472eSBen Skeggs  * INIT_COPY_ZM_REG - opcode 0x90
2015c39f472eSBen Skeggs  *
2016c39f472eSBen Skeggs  */
2017c39f472eSBen Skeggs static void
init_copy_zm_reg(struct nvbios_init * init)2018c39f472eSBen Skeggs init_copy_zm_reg(struct nvbios_init *init)
2019c39f472eSBen Skeggs {
20205b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
20217f5f518fSBen Skeggs 	u32 sreg = nvbios_rd32(bios, init->offset + 1);
20227f5f518fSBen Skeggs 	u32 dreg = nvbios_rd32(bios, init->offset + 5);
2023c39f472eSBen Skeggs 
2024c39f472eSBen Skeggs 	trace("COPY_ZM_REG\tR[0x%06x] = R[0x%06x]\n", dreg, sreg);
2025c39f472eSBen Skeggs 	init->offset += 9;
2026c39f472eSBen Skeggs 
2027c39f472eSBen Skeggs 	init_wr32(init, dreg, init_rd32(init, sreg));
2028c39f472eSBen Skeggs }
2029c39f472eSBen Skeggs 
2030c39f472eSBen Skeggs /**
2031c39f472eSBen Skeggs  * INIT_ZM_REG_GROUP - opcode 0x91
2032c39f472eSBen Skeggs  *
2033c39f472eSBen Skeggs  */
2034c39f472eSBen Skeggs static void
init_zm_reg_group(struct nvbios_init * init)2035c39f472eSBen Skeggs init_zm_reg_group(struct nvbios_init *init)
2036c39f472eSBen Skeggs {
20375b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
20387f5f518fSBen Skeggs 	u32 addr = nvbios_rd32(bios, init->offset + 1);
20397f5f518fSBen Skeggs 	u8 count = nvbios_rd08(bios, init->offset + 5);
2040c39f472eSBen Skeggs 
2041c39f472eSBen Skeggs 	trace("ZM_REG_GROUP\tR[0x%06x] =\n", addr);
2042c39f472eSBen Skeggs 	init->offset += 6;
2043c39f472eSBen Skeggs 
2044c39f472eSBen Skeggs 	while (count--) {
20457f5f518fSBen Skeggs 		u32 data = nvbios_rd32(bios, init->offset);
2046c39f472eSBen Skeggs 		trace("\t0x%08x\n", data);
2047c39f472eSBen Skeggs 		init_wr32(init, addr, data);
2048c39f472eSBen Skeggs 		init->offset += 4;
2049c39f472eSBen Skeggs 	}
2050c39f472eSBen Skeggs }
2051c39f472eSBen Skeggs 
2052c39f472eSBen Skeggs /**
2053c39f472eSBen Skeggs  * INIT_XLAT - opcode 0x96
2054c39f472eSBen Skeggs  *
2055c39f472eSBen Skeggs  */
2056c39f472eSBen Skeggs static void
init_xlat(struct nvbios_init * init)2057c39f472eSBen Skeggs init_xlat(struct nvbios_init *init)
2058c39f472eSBen Skeggs {
20595b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
20607f5f518fSBen Skeggs 	u32 saddr = nvbios_rd32(bios, init->offset + 1);
20617f5f518fSBen Skeggs 	u8 sshift = nvbios_rd08(bios, init->offset + 5);
20627f5f518fSBen Skeggs 	u8  smask = nvbios_rd08(bios, init->offset + 6);
20637f5f518fSBen Skeggs 	u8  index = nvbios_rd08(bios, init->offset + 7);
20647f5f518fSBen Skeggs 	u32 daddr = nvbios_rd32(bios, init->offset + 8);
20657f5f518fSBen Skeggs 	u32 dmask = nvbios_rd32(bios, init->offset + 12);
20667f5f518fSBen Skeggs 	u8  shift = nvbios_rd08(bios, init->offset + 16);
2067c39f472eSBen Skeggs 	u32 data;
2068c39f472eSBen Skeggs 
2069c39f472eSBen Skeggs 	trace("INIT_XLAT\tR[0x%06x] &= 0x%08x |= "
2070c39f472eSBen Skeggs 	      "(X%02x((R[0x%06x] %s 0x%02x) & 0x%02x) << 0x%02x)\n",
2071c39f472eSBen Skeggs 	      daddr, dmask, index, saddr, (sshift & 0x80) ? "<<" : ">>",
2072c39f472eSBen Skeggs 	      (sshift & 0x80) ? (0x100 - sshift) : sshift, smask, shift);
2073c39f472eSBen Skeggs 	init->offset += 17;
2074c39f472eSBen Skeggs 
2075c39f472eSBen Skeggs 	data = init_shift(init_rd32(init, saddr), sshift) & smask;
2076c39f472eSBen Skeggs 	data = init_xlat_(init, index, data) << shift;
2077c39f472eSBen Skeggs 	init_mask(init, daddr, ~dmask, data);
2078c39f472eSBen Skeggs }
2079c39f472eSBen Skeggs 
2080c39f472eSBen Skeggs /**
2081c39f472eSBen Skeggs  * INIT_ZM_MASK_ADD - opcode 0x97
2082c39f472eSBen Skeggs  *
2083c39f472eSBen Skeggs  */
2084c39f472eSBen Skeggs static void
init_zm_mask_add(struct nvbios_init * init)2085c39f472eSBen Skeggs init_zm_mask_add(struct nvbios_init *init)
2086c39f472eSBen Skeggs {
20875b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
20887f5f518fSBen Skeggs 	u32 addr = nvbios_rd32(bios, init->offset + 1);
20897f5f518fSBen Skeggs 	u32 mask = nvbios_rd32(bios, init->offset + 5);
20907f5f518fSBen Skeggs 	u32  add = nvbios_rd32(bios, init->offset + 9);
2091c39f472eSBen Skeggs 	u32 data;
2092c39f472eSBen Skeggs 
2093c39f472eSBen Skeggs 	trace("ZM_MASK_ADD\tR[0x%06x] &= 0x%08x += 0x%08x\n", addr, mask, add);
2094c39f472eSBen Skeggs 	init->offset += 13;
2095c39f472eSBen Skeggs 
2096c39f472eSBen Skeggs 	data =  init_rd32(init, addr);
2097c39f472eSBen Skeggs 	data = (data & mask) | ((data + add) & ~mask);
2098c39f472eSBen Skeggs 	init_wr32(init, addr, data);
2099c39f472eSBen Skeggs }
2100c39f472eSBen Skeggs 
2101c39f472eSBen Skeggs /**
2102c39f472eSBen Skeggs  * INIT_AUXCH - opcode 0x98
2103c39f472eSBen Skeggs  *
2104c39f472eSBen Skeggs  */
2105c39f472eSBen Skeggs static void
init_auxch(struct nvbios_init * init)2106c39f472eSBen Skeggs init_auxch(struct nvbios_init *init)
2107c39f472eSBen Skeggs {
21085b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
21097f5f518fSBen Skeggs 	u32 addr = nvbios_rd32(bios, init->offset + 1);
21107f5f518fSBen Skeggs 	u8 count = nvbios_rd08(bios, init->offset + 5);
2111c39f472eSBen Skeggs 
2112c39f472eSBen Skeggs 	trace("AUXCH\tAUX[0x%08x] 0x%02x\n", addr, count);
2113c39f472eSBen Skeggs 	init->offset += 6;
2114c39f472eSBen Skeggs 
2115c39f472eSBen Skeggs 	while (count--) {
21167f5f518fSBen Skeggs 		u8 mask = nvbios_rd08(bios, init->offset + 0);
21177f5f518fSBen Skeggs 		u8 data = nvbios_rd08(bios, init->offset + 1);
2118c39f472eSBen Skeggs 		trace("\tAUX[0x%08x] &= 0x%02x |= 0x%02x\n", addr, mask, data);
2119c39f472eSBen Skeggs 		mask = init_rdauxr(init, addr) & mask;
2120c39f472eSBen Skeggs 		init_wrauxr(init, addr, mask | data);
2121c39f472eSBen Skeggs 		init->offset += 2;
2122c39f472eSBen Skeggs 	}
2123c39f472eSBen Skeggs }
2124c39f472eSBen Skeggs 
2125c39f472eSBen Skeggs /**
2126c39f472eSBen Skeggs  * INIT_AUXCH - opcode 0x99
2127c39f472eSBen Skeggs  *
2128c39f472eSBen Skeggs  */
2129c39f472eSBen Skeggs static void
init_zm_auxch(struct nvbios_init * init)2130c39f472eSBen Skeggs init_zm_auxch(struct nvbios_init *init)
2131c39f472eSBen Skeggs {
21325b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
21337f5f518fSBen Skeggs 	u32 addr = nvbios_rd32(bios, init->offset + 1);
21347f5f518fSBen Skeggs 	u8 count = nvbios_rd08(bios, init->offset + 5);
2135c39f472eSBen Skeggs 
2136c39f472eSBen Skeggs 	trace("ZM_AUXCH\tAUX[0x%08x] 0x%02x\n", addr, count);
2137c39f472eSBen Skeggs 	init->offset += 6;
2138c39f472eSBen Skeggs 
2139c39f472eSBen Skeggs 	while (count--) {
21407f5f518fSBen Skeggs 		u8 data = nvbios_rd08(bios, init->offset + 0);
2141c39f472eSBen Skeggs 		trace("\tAUX[0x%08x] = 0x%02x\n", addr, data);
2142c39f472eSBen Skeggs 		init_wrauxr(init, addr, data);
2143c39f472eSBen Skeggs 		init->offset += 1;
2144c39f472eSBen Skeggs 	}
2145c39f472eSBen Skeggs }
2146c39f472eSBen Skeggs 
2147c39f472eSBen Skeggs /**
2148c39f472eSBen Skeggs  * INIT_I2C_LONG_IF - opcode 0x9a
2149c39f472eSBen Skeggs  *
2150c39f472eSBen Skeggs  */
2151c39f472eSBen Skeggs static void
init_i2c_long_if(struct nvbios_init * init)2152c39f472eSBen Skeggs init_i2c_long_if(struct nvbios_init *init)
2153c39f472eSBen Skeggs {
21545b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
21557f5f518fSBen Skeggs 	u8 index = nvbios_rd08(bios, init->offset + 1);
21567f5f518fSBen Skeggs 	u8  addr = nvbios_rd08(bios, init->offset + 2) >> 1;
21577f5f518fSBen Skeggs 	u8 reglo = nvbios_rd08(bios, init->offset + 3);
21587f5f518fSBen Skeggs 	u8 reghi = nvbios_rd08(bios, init->offset + 4);
21597f5f518fSBen Skeggs 	u8  mask = nvbios_rd08(bios, init->offset + 5);
21607f5f518fSBen Skeggs 	u8  data = nvbios_rd08(bios, init->offset + 6);
21612aa5eac5SBen Skeggs 	struct i2c_adapter *adap;
2162c39f472eSBen Skeggs 
2163c39f472eSBen Skeggs 	trace("I2C_LONG_IF\t"
2164c39f472eSBen Skeggs 	      "I2C[0x%02x][0x%02x][0x%02x%02x] & 0x%02x == 0x%02x\n",
2165c39f472eSBen Skeggs 	      index, addr, reglo, reghi, mask, data);
2166c39f472eSBen Skeggs 	init->offset += 7;
2167c39f472eSBen Skeggs 
21682aa5eac5SBen Skeggs 	adap = init_i2c(init, index);
21692aa5eac5SBen Skeggs 	if (adap) {
2170c39f472eSBen Skeggs 		u8 i[2] = { reghi, reglo };
2171c39f472eSBen Skeggs 		u8 o[1] = {};
2172c39f472eSBen Skeggs 		struct i2c_msg msg[] = {
2173c39f472eSBen Skeggs 			{ .addr = addr, .flags = 0, .len = 2, .buf = i },
2174c39f472eSBen Skeggs 			{ .addr = addr, .flags = I2C_M_RD, .len = 1, .buf = o }
2175c39f472eSBen Skeggs 		};
2176c39f472eSBen Skeggs 		int ret;
2177c39f472eSBen Skeggs 
21782aa5eac5SBen Skeggs 		ret = i2c_transfer(adap, msg, 2);
2179c39f472eSBen Skeggs 		if (ret == 2 && ((o[0] & mask) == data))
2180c39f472eSBen Skeggs 			return;
2181c39f472eSBen Skeggs 	}
2182c39f472eSBen Skeggs 
2183c39f472eSBen Skeggs 	init_exec_set(init, false);
2184c39f472eSBen Skeggs }
2185c39f472eSBen Skeggs 
2186c39f472eSBen Skeggs /**
2187c39f472eSBen Skeggs  * INIT_GPIO_NE - opcode 0xa9
2188c39f472eSBen Skeggs  *
2189c39f472eSBen Skeggs  */
2190c39f472eSBen Skeggs static void
init_gpio_ne(struct nvbios_init * init)2191c39f472eSBen Skeggs init_gpio_ne(struct nvbios_init *init)
2192c39f472eSBen Skeggs {
21935b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
219446484438SBen Skeggs 	struct nvkm_gpio *gpio = bios->subdev.device->gpio;
2195c39f472eSBen Skeggs 	struct dcb_gpio_func func;
21967f5f518fSBen Skeggs 	u8 count = nvbios_rd08(bios, init->offset + 1);
2197c39f472eSBen Skeggs 	u8 idx = 0, ver, len;
2198c39f472eSBen Skeggs 	u16 data, i;
2199c39f472eSBen Skeggs 
2200c39f472eSBen Skeggs 	trace("GPIO_NE\t");
2201c39f472eSBen Skeggs 	init->offset += 2;
2202c39f472eSBen Skeggs 
2203c39f472eSBen Skeggs 	for (i = init->offset; i < init->offset + count; i++)
22047f5f518fSBen Skeggs 		cont("0x%02x ", nvbios_rd08(bios, i));
2205c39f472eSBen Skeggs 	cont("\n");
2206c39f472eSBen Skeggs 
2207c39f472eSBen Skeggs 	while ((data = dcb_gpio_parse(bios, 0, idx++, &ver, &len, &func))) {
2208c39f472eSBen Skeggs 		if (func.func != DCB_GPIO_UNUSED) {
2209c39f472eSBen Skeggs 			for (i = init->offset; i < init->offset + count; i++) {
22107f5f518fSBen Skeggs 				if (func.func == nvbios_rd08(bios, i))
2211c39f472eSBen Skeggs 					break;
2212c39f472eSBen Skeggs 			}
2213c39f472eSBen Skeggs 
2214c39f472eSBen Skeggs 			trace("\tFUNC[0x%02x]", func.func);
2215c39f472eSBen Skeggs 			if (i == (init->offset + count)) {
2216c39f472eSBen Skeggs 				cont(" *");
22172ea7249fSBen Skeggs 				if (init_exec(init))
22182ea7249fSBen Skeggs 					nvkm_gpio_reset(gpio, func.func);
2219c39f472eSBen Skeggs 			}
2220c39f472eSBen Skeggs 			cont("\n");
2221c39f472eSBen Skeggs 		}
2222c39f472eSBen Skeggs 	}
2223c39f472eSBen Skeggs 
2224c39f472eSBen Skeggs 	init->offset += count;
2225c39f472eSBen Skeggs }
2226c39f472eSBen Skeggs 
2227c39f472eSBen Skeggs static struct nvbios_init_opcode {
2228c39f472eSBen Skeggs 	void (*exec)(struct nvbios_init *);
2229c39f472eSBen Skeggs } init_opcode[] = {
2230c39f472eSBen Skeggs 	[0x32] = { init_io_restrict_prog },
2231c39f472eSBen Skeggs 	[0x33] = { init_repeat },
2232c39f472eSBen Skeggs 	[0x34] = { init_io_restrict_pll },
2233c39f472eSBen Skeggs 	[0x36] = { init_end_repeat },
2234c39f472eSBen Skeggs 	[0x37] = { init_copy },
2235c39f472eSBen Skeggs 	[0x38] = { init_not },
2236c39f472eSBen Skeggs 	[0x39] = { init_io_flag_condition },
2237989f5784SBen Skeggs 	[0x3a] = { init_generic_condition },
2238c39f472eSBen Skeggs 	[0x3b] = { init_io_mask_or },
2239c39f472eSBen Skeggs 	[0x3c] = { init_io_or },
2240c39f472eSBen Skeggs 	[0x47] = { init_andn_reg },
2241c39f472eSBen Skeggs 	[0x48] = { init_or_reg },
2242c39f472eSBen Skeggs 	[0x49] = { init_idx_addr_latched },
2243c39f472eSBen Skeggs 	[0x4a] = { init_io_restrict_pll2 },
2244c39f472eSBen Skeggs 	[0x4b] = { init_pll2 },
2245c39f472eSBen Skeggs 	[0x4c] = { init_i2c_byte },
2246c39f472eSBen Skeggs 	[0x4d] = { init_zm_i2c_byte },
2247c39f472eSBen Skeggs 	[0x4e] = { init_zm_i2c },
2248c39f472eSBen Skeggs 	[0x4f] = { init_tmds },
2249c39f472eSBen Skeggs 	[0x50] = { init_zm_tmds_group },
2250c39f472eSBen Skeggs 	[0x51] = { init_cr_idx_adr_latch },
2251c39f472eSBen Skeggs 	[0x52] = { init_cr },
2252c39f472eSBen Skeggs 	[0x53] = { init_zm_cr },
2253c39f472eSBen Skeggs 	[0x54] = { init_zm_cr_group },
2254c39f472eSBen Skeggs 	[0x56] = { init_condition_time },
2255c39f472eSBen Skeggs 	[0x57] = { init_ltime },
2256c39f472eSBen Skeggs 	[0x58] = { init_zm_reg_sequence },
2257d31b11d8SIlia Mirkin 	[0x59] = { init_pll_indirect },
2258360ccb84SIlia Mirkin 	[0x5a] = { init_zm_reg_indirect },
2259c39f472eSBen Skeggs 	[0x5b] = { init_sub_direct },
2260c39f472eSBen Skeggs 	[0x5c] = { init_jump },
2261c39f472eSBen Skeggs 	[0x5e] = { init_i2c_if },
2262c39f472eSBen Skeggs 	[0x5f] = { init_copy_nv_reg },
2263c39f472eSBen Skeggs 	[0x62] = { init_zm_index_io },
2264c39f472eSBen Skeggs 	[0x63] = { init_compute_mem },
2265c39f472eSBen Skeggs 	[0x65] = { init_reset },
2266c39f472eSBen Skeggs 	[0x66] = { init_configure_mem },
2267c39f472eSBen Skeggs 	[0x67] = { init_configure_clk },
2268c39f472eSBen Skeggs 	[0x68] = { init_configure_preinit },
2269c39f472eSBen Skeggs 	[0x69] = { init_io },
2270c39f472eSBen Skeggs 	[0x6b] = { init_sub },
2271c39f472eSBen Skeggs 	[0x6d] = { init_ram_condition },
2272c39f472eSBen Skeggs 	[0x6e] = { init_nv_reg },
2273c39f472eSBen Skeggs 	[0x6f] = { init_macro },
2274c39f472eSBen Skeggs 	[0x71] = { init_done },
2275c39f472eSBen Skeggs 	[0x72] = { init_resume },
2276bacbad17SIlia Mirkin 	[0x73] = { init_strap_condition },
2277c39f472eSBen Skeggs 	[0x74] = { init_time },
2278c39f472eSBen Skeggs 	[0x75] = { init_condition },
2279c39f472eSBen Skeggs 	[0x76] = { init_io_condition },
2280bacbad17SIlia Mirkin 	[0x77] = { init_zm_reg16 },
2281c39f472eSBen Skeggs 	[0x78] = { init_index_io },
2282c39f472eSBen Skeggs 	[0x79] = { init_pll },
2283c39f472eSBen Skeggs 	[0x7a] = { init_zm_reg },
2284c39f472eSBen Skeggs 	[0x87] = { init_ram_restrict_pll },
228566cbcc72SRhys Kidd 	[0x8c] = { init_reset_begun },
22869f9b4507SRhys Kidd 	[0x8d] = { init_reset_end },
2287c39f472eSBen Skeggs 	[0x8e] = { init_gpio },
2288c39f472eSBen Skeggs 	[0x8f] = { init_ram_restrict_zm_reg_group },
2289c39f472eSBen Skeggs 	[0x90] = { init_copy_zm_reg },
2290c39f472eSBen Skeggs 	[0x91] = { init_zm_reg_group },
2291c39f472eSBen Skeggs 	[0x92] = { init_reserved },
2292c39f472eSBen Skeggs 	[0x96] = { init_xlat },
2293c39f472eSBen Skeggs 	[0x97] = { init_zm_mask_add },
2294c39f472eSBen Skeggs 	[0x98] = { init_auxch },
2295c39f472eSBen Skeggs 	[0x99] = { init_zm_auxch },
2296c39f472eSBen Skeggs 	[0x9a] = { init_i2c_long_if },
2297c39f472eSBen Skeggs 	[0xa9] = { init_gpio_ne },
2298c39f472eSBen Skeggs 	[0xaa] = { init_reserved },
2299c39f472eSBen Skeggs };
2300c39f472eSBen Skeggs 
2301c39f472eSBen Skeggs int
nvbios_exec(struct nvbios_init * init)2302c39f472eSBen Skeggs nvbios_exec(struct nvbios_init *init)
2303c39f472eSBen Skeggs {
23045b0e787aSBen Skeggs 	struct nvkm_bios *bios = init->subdev->device->bios;
2305b88afa43SBen Skeggs 
2306c39f472eSBen Skeggs 	init->nested++;
2307c39f472eSBen Skeggs 	while (init->offset) {
23085b0e787aSBen Skeggs 		u8 opcode = nvbios_rd08(bios, init->offset);
230973cef6ceSJérémy Lefaure 		if (opcode >= ARRAY_SIZE(init_opcode) ||
231073cef6ceSJérémy Lefaure 		    !init_opcode[opcode].exec) {
2311c39f472eSBen Skeggs 			error("unknown opcode 0x%02x\n", opcode);
2312c39f472eSBen Skeggs 			return -EINVAL;
2313c39f472eSBen Skeggs 		}
2314c39f472eSBen Skeggs 
2315c39f472eSBen Skeggs 		init_opcode[opcode].exec(init);
2316c39f472eSBen Skeggs 	}
2317c39f472eSBen Skeggs 	init->nested--;
2318c39f472eSBen Skeggs 	return 0;
2319c39f472eSBen Skeggs }
2320c39f472eSBen Skeggs 
2321c39f472eSBen Skeggs int
nvbios_post(struct nvkm_subdev * subdev,bool execute)23224bb4a746SBen Skeggs nvbios_post(struct nvkm_subdev *subdev, bool execute)
2323c39f472eSBen Skeggs {
232446484438SBen Skeggs 	struct nvkm_bios *bios = subdev->device->bios;
2325c39f472eSBen Skeggs 	int ret = 0;
2326c39f472eSBen Skeggs 	int i = -1;
2327c39f472eSBen Skeggs 	u16 data;
2328c39f472eSBen Skeggs 
2329c39f472eSBen Skeggs 	if (execute)
233060b29d20SBen Skeggs 		nvkm_debug(subdev, "running init tables\n");
2331c39f472eSBen Skeggs 	while (!ret && (data = (init_script(bios, ++i)))) {
233228c62976SBen Skeggs 		ret = nvbios_init(subdev, data,
233328c62976SBen Skeggs 			init.execute = execute ? 1 : 0;
233428c62976SBen Skeggs 		      );
2335c39f472eSBen Skeggs 	}
2336c39f472eSBen Skeggs 
2337c39f472eSBen Skeggs 	/* the vbios parser will run this right after the normal init
2338c39f472eSBen Skeggs 	 * tables, whereas the binary driver appears to run it later.
2339c39f472eSBen Skeggs 	 */
2340c39f472eSBen Skeggs 	if (!ret && (data = init_unknown_script(bios))) {
234128c62976SBen Skeggs 		ret = nvbios_init(subdev, data,
234228c62976SBen Skeggs 			init.execute = execute ? 1 : 0;
234328c62976SBen Skeggs 		      );
2344c39f472eSBen Skeggs 	}
2345c39f472eSBen Skeggs 
2346c39f472eSBen Skeggs 	return ret;
2347c39f472eSBen Skeggs }
2348