View | Details | Raw Unified | Return to bug 238037 | Differences between
and this patch

Collapse All | Expand All

(-)sys/dev/ichiic/ig4_acpi.c (+2 lines)
Lines 153-158 Link Here
153
	DEVMETHOD(device_probe, ig4iic_acpi_probe),
153
	DEVMETHOD(device_probe, ig4iic_acpi_probe),
154
	DEVMETHOD(device_attach, ig4iic_acpi_attach),
154
	DEVMETHOD(device_attach, ig4iic_acpi_attach),
155
	DEVMETHOD(device_detach, ig4iic_acpi_detach),
155
	DEVMETHOD(device_detach, ig4iic_acpi_detach),
156
	DEVMETHOD(device_suspend, bus_generic_suspend),
157
	DEVMETHOD(device_resume, bus_generic_resume),
156
158
157
	/* iicbus interface */
159
	/* iicbus interface */
158
	DEVMETHOD(iicbus_transfer, ig4iic_transfer),
160
	DEVMETHOD(iicbus_transfer, ig4iic_transfer),
(-)sys/dev/ichiic/ig4_pci.c (+109 lines)
Lines 206-216 Link Here
206
	return (0);
206
	return (0);
207
}
207
}
208
208
209
/*
210
 * During suspend we save registers and re-initialize them
211
 * during resume. This is a list of the registers to save.
212
 *
213
 * IG4_REGS_CONTEXT_SIZE is the length of this array.
214
 *   It must be updated if this list is.
215
 *
216
 * The regs_context field of struct ig4iic_softc holds the
217
 * values of the saved registers.
218
 */
219
uint32_t regs_context_ids[IG4_REGS_CONTEXT_SIZE] = {
220
	IG4_REG_CTL,
221
	IG4_REG_TAR_ADD,
222
	IG4_REG_DATA_CMD,
223
	IG4_REG_SS_SCL_HCNT,
224
	IG4_REG_SS_SCL_LCNT,
225
	IG4_REG_FS_SCL_HCNT,
226
	IG4_REG_FS_SCL_LCNT,
227
	IG4_REG_INTR_MASK,
228
	IG4_REG_RX_TL,
229
	IG4_REG_TX_TL,
230
	IG4_REG_I2C_EN,
231
	IG4_REG_SDA_HOLD,
232
	IG4_REG_SLV_DATA_NACK,
233
	IG4_REG_DMA_CTRL,
234
	IG4_REG_DMA_TDLR,
235
	IG4_REG_DMA_RDLR,
236
	IG4_REG_SDA_SETUP,
237
	IG4_REG_GENERAL,
238
	IG4_REG_ACK_GENERAL_CALL,
239
	IG4_REG_SW_LTR_VALUE,
240
	IG4_REG_AUTO_LTR_VALUE,
241
};
242
243
static int
244
ig4iic_pci_suspend(device_t dev)
245
{
246
	ig4iic_softc_t *sc;
247
248
	sc = device_get_softc(dev);
249
250
	/* RESETS spec (22.2.36) recommends saving and re-initializing registers */
251
	for (int i = 0; i < IG4_REGS_CONTEXT_SIZE; i++) {
252
		bus_barrier(sc->regs_res, regs_context_ids[i], 4, BUS_SPACE_BARRIER_READ);
253
		sc->regs_context[i] = bus_read_4(sc->regs_res, regs_context_ids[i]);
254
	}
255
256
	/* 
257
	 * reset the controller before we suspend 
258
	 * Haswell and Skylake apparently have different RESET methods
259
	 */
260
	if (sc->version == IG4_HASWELL || sc->version == IG4_ATOM) {
261
		bus_write_4(sc->regs_res, IG4_REG_RESETS_HSW, IG4_RESETS_ASSERT_HSW);
262
		bus_barrier(sc->regs_res, IG4_REG_RESETS_HSW, 4, BUS_SPACE_BARRIER_WRITE);
263
		
264
	} else if (sc->version == IG4_SKYLAKE) {
265
		/* 
266
		 *
267
		 * set IG4_DEVICE_IDLE and IG4_RESTORE_REQUIRED 
268
		 * to place the device in the idle state, just to be safe
269
		 */
270
		bus_write_4(sc->regs_res, IG4_REG_DEVIDLE_CTRL,
271
			    IG4_DEVICE_IDLE | IG4_RESTORE_REQUIRED);
272
273
		bus_write_4(sc->regs_res, IG4_REG_RESETS_SKL, IG4_RESETS_ASSERT_SKL);
274
		bus_barrier(sc->regs_res, IG4_REG_RESETS_SKL, 4, BUS_SPACE_BARRIER_WRITE);
275
		
276
	} else {
277
		device_printf(dev, "Unable to assert reset, reset register unavailable\n");
278
	}
279
280
	/* suspend all children */
281
	return bus_generic_suspend(dev);
282
}
283
284
static int
285
ig4iic_pci_resume(device_t dev)
286
{
287
	ig4iic_softc_t *sc;
288
289
	sc = device_get_softc(dev);
290
291
	/* wake the controller before its children */
292
	if (sc->version == IG4_HASWELL || sc->version == IG4_ATOM) {
293
		bus_write_4(sc->regs_res, IG4_REG_RESETS_HSW, IG4_RESETS_DEASSERT_HSW);
294
		bus_barrier(sc->regs_res, IG4_REG_RESETS_HSW, 4, BUS_SPACE_BARRIER_WRITE);
295
		
296
	} else if (sc->version == IG4_SKYLAKE) {
297
		/* unset IG4_DEVICE_IDLE  */
298
		bus_write_4(sc->regs_res, IG4_REG_DEVIDLE_CTRL, 0);
299
		
300
		bus_write_4(sc->regs_res, IG4_REG_RESETS_SKL, IG4_RESETS_DEASSERT_SKL);
301
		bus_barrier(sc->regs_res, IG4_REG_RESETS_SKL, 4, BUS_SPACE_BARRIER_WRITE);
302
		
303
	} else {
304
		device_printf(dev, "Unable to deassert reset, reset register unavailable\n");
305
	}
306
	
307
	/* set registers to values previously saved in regs_context */
308
	for (int i = 0; i < IG4_REGS_CONTEXT_SIZE; i++) {
309
		bus_write_4(sc->regs_res, regs_context_ids[i], sc->regs_context[i]);
310
		bus_barrier(sc->regs_res, regs_context_ids[i], 4, BUS_SPACE_BARRIER_WRITE);
311
	}
312
313
	return bus_generic_resume(dev);
314
}
315
209
static device_method_t ig4iic_pci_methods[] = {
316
static device_method_t ig4iic_pci_methods[] = {
210
	/* Device interface */
317
	/* Device interface */
211
	DEVMETHOD(device_probe, ig4iic_pci_probe),
318
	DEVMETHOD(device_probe, ig4iic_pci_probe),
212
	DEVMETHOD(device_attach, ig4iic_pci_attach),
319
	DEVMETHOD(device_attach, ig4iic_pci_attach),
213
	DEVMETHOD(device_detach, ig4iic_pci_detach),
320
	DEVMETHOD(device_detach, ig4iic_pci_detach),
321
	DEVMETHOD(device_suspend, ig4iic_pci_suspend),
322
	DEVMETHOD(device_resume, ig4iic_pci_resume),
214
323
215
	DEVMETHOD(iicbus_transfer, ig4iic_transfer),
324
	DEVMETHOD(iicbus_transfer, ig4iic_transfer),
216
	DEVMETHOD(iicbus_reset, ig4iic_reset),
325
	DEVMETHOD(iicbus_reset, ig4iic_reset),
(-)sys/dev/ichiic/ig4_var.h (+4 lines)
Lines 49-54 Link Here
49
enum ig4_op { IG4_IDLE, IG4_READ, IG4_WRITE };
49
enum ig4_op { IG4_IDLE, IG4_READ, IG4_WRITE };
50
enum ig4_vers { IG4_HASWELL, IG4_ATOM, IG4_SKYLAKE, IG4_APL };
50
enum ig4_vers { IG4_HASWELL, IG4_ATOM, IG4_SKYLAKE, IG4_APL };
51
51
52
/* length of the register context array (regs_context_ids) */
53
#define IG4_REGS_CONTEXT_SIZE 21
54
52
struct ig4iic_softc {
55
struct ig4iic_softc {
53
	device_t	dev;
56
	device_t	dev;
54
	struct		intr_config_hook enum_hook;
57
	struct		intr_config_hook enum_hook;
Lines 55-60 Link Here
55
	device_t	iicbus;
58
	device_t	iicbus;
56
	struct resource	*regs_res;
59
	struct resource	*regs_res;
57
	int		regs_rid;
60
	int		regs_rid;
61
	uint32_t	regs_context[IG4_REGS_CONTEXT_SIZE];
58
	struct resource	*intr_res;
62
	struct resource	*intr_res;
59
	int		intr_rid;
63
	int		intr_rid;
60
	void		*intr_handle;
64
	void		*intr_handle;

Return to bug 238037