2 * Copyright (c) 2009,2010 One Laptop per Child
4 * This program is free software. You can redistribute it and/or
5 * modify it under the terms of version 2 of the GNU General Public
6 * License as published by the Free Software Foundation.
9 #include <linux/acpi.h>
11 /* Hardware setup on the XO 1.5:
12 * DCONLOAD connects to
13 * VX855_GPO12 (not nCR_PWOFF) (rev A)
14 * VX855_GPIO1 (not SMBCK2) (rev B)
15 * DCONBLANK connects to VX855_GPIO8 (not SSPICLK) unused in driver
16 * DCONSTAT0 connects to VX855_GPI10 (not SSPISDI)
17 * DCONSTAT1 connects to VX855_GPI11 (not nSSPISS)
18 * DCONIRQ connects to VX855_GPIO12 (on B3. on B2, it goes to
19 * SMBALRT, which doesn't work.)
20 * DCONSMBDATA connects to VX855 graphics CRTSPD
21 * DCONSMBCLK connects to VX855 graphics CRTSPCLK
24 #define TEST_B2 0 // define to test B3 paths on a modded B2 board
26 #define VX855_GENL_PURPOSE_OUTPUT 0x44c // PMIO_Rx4c-4f
27 #define VX855_GPI_STATUS_CHG 0x450 // PMIO_Rx50
28 #define VX855_GPI_SCI_SMI 0x452 // PMIO_Rx52
29 #define BIT_GPIO12 0x40
31 #define PREFIX "OLPC DCON:"
34 there is no support here for DCONIRQ on 1.5 boards earlier than
35 B3. the issue is that the DCONIRQ signal on earlier boards is
36 routed to SMBALRT, which turns out to to be a level sensitive
37 interrupt. the DCONIRQ signal is far too short (11usec) to
38 be detected reliably in that case. including support for
39 DCONIRQ functions no better than none at all.
42 static struct dcon_platform_data dcon_pdata_xo_1_5;
44 static void dcon_clear_irq(void)
46 if (TEST_B2 || olpc_board_at_least(olpc_board(BOARD_XO_1_5_B3))) {
47 // irq status will appear in PMIO_Rx50[6] (RW1C) on gpio12
48 outb(BIT_GPIO12, VX855_GPI_STATUS_CHG);
52 static int dcon_was_irq(void)
56 if (TEST_B2 || olpc_board_at_least(olpc_board(BOARD_XO_1_5_B3))) {
57 // irq status will appear in PMIO_Rx50[6] on gpio12
58 tmp = inb(VX855_GPI_STATUS_CHG);
59 return !!(tmp & BIT_GPIO12);
65 static int dcon_init_xo_1_5(void)
72 pdev = pci_get_device(PCI_VENDOR_ID_VIA,
73 PCI_DEVICE_ID_VIA_VX855, NULL);
75 printk(KERN_ERR "cannot find VX855 PCI ID\n");
79 if (olpc_board_at_least(olpc_board(BOARD_XO_1_5_B1))) {
80 pci_read_config_byte(pdev, 0x95, &tmp);
81 pci_write_config_byte(pdev, 0x95, tmp|0x0c);
83 /* Set GPO12 to GPO mode, not nCR_PWOFF */
84 pci_read_config_byte(pdev, 0x9b, &tmp);
85 pci_write_config_byte(pdev, 0x9b, tmp|0x01);
88 /* Set GPIO8 to GPIO mode, not SSPICLK */
89 pci_read_config_byte(pdev, 0xe3, &tmp);
90 pci_write_config_byte(pdev, 0xe3, tmp | 0x04);
92 /* Set GPI10/GPI11 to GPI mode, not SSPISDI/SSPISS */
93 pci_read_config_byte(pdev, 0xe4, &tmp);
94 pci_write_config_byte(pdev, 0xe4, tmp|0x08);
96 if (TEST_B2 || olpc_board_at_least(olpc_board(BOARD_XO_1_5_B3))) {
97 // clear PMU_RxE1[6] to select SCI on GPIO12
98 // clear PMU_RxE0[6] to choose falling edge
99 pci_read_config_byte(pdev, 0xe1, &tmp);
100 pci_write_config_byte(pdev, 0xe1, tmp & ~BIT_GPIO12);
101 pci_read_config_byte(pdev, 0xe0, &tmp);
102 pci_write_config_byte(pdev, 0xe0, tmp & ~BIT_GPIO12);
106 // set PMIO_Rx52[6] to enable SCI/SMI on gpio12
107 outb(inb(VX855_GPI_SCI_SMI)|BIT_GPIO12, VX855_GPI_SCI_SMI);
111 /* Determine the current state of DCONLOAD, likely set by firmware */
112 if (olpc_board_at_least(olpc_board(BOARD_XO_1_5_B1))) {
114 dcon_source = (inl(VX855_GENL_PURPOSE_OUTPUT) & 0x1000) ?
115 DCON_SOURCE_CPU : DCON_SOURCE_DCON;
118 dcon_source = (inl(VX855_GENL_PURPOSE_OUTPUT) & 0x04000000) ?
119 DCON_SOURCE_CPU : DCON_SOURCE_DCON;
121 dcon_pending = dcon_source;
125 /* we're sharing the IRQ with ACPI */
126 irq = acpi_gbl_FADT.sci_interrupt;
127 if (request_irq(irq, &dcon_interrupt, IRQF_SHARED, "DCON", &dcon_driver)) {
128 printk(KERN_ERR PREFIX "DCON (IRQ%d) allocation failed\n", irq);
136 static void set_i2c_line(int sda, int scl)
139 unsigned int port = 0x26;
141 /* FIXME: This directly accesses the CRT GPIO controller !!! */
162 static void dcon_wiggle_xo_1_5(void)
167 * According to HiMax, when powering the DCON up we should hold
168 * SMB_DATA high for 8 SMB_CLK cycles. This will force the DCON
169 * state machine to reset to a (sane) initial state. Mitch Bradley
170 * did some testing and discovered that holding for 16 SMB_CLK cycles
171 * worked a lot more reliably, so that's what we do here.
175 for (x = 0; x < 16; x++) {
183 if (TEST_B2 || olpc_board_at_least(olpc_board(BOARD_XO_1_5_B3))) {
184 // set PMIO_Rx52[6] to enable SCI/SMI on gpio12
185 outb(inb(VX855_GPI_SCI_SMI)|BIT_GPIO12, VX855_GPI_SCI_SMI);
189 static void dcon_set_dconload_xo_1_5(int val)
191 if (olpc_board_at_least(olpc_board(BOARD_XO_1_5_B1))) {
192 gpio_set_value(VX855_GPIO(1), val);
194 gpio_set_value(VX855_GPO(12), val);
198 static u8 dcon_read_status_xo_1_5(void)
205 // i believe this is the same as "inb(0x44b) & 3"
206 status = gpio_get_value(VX855_GPI(10));
207 status |= gpio_get_value(VX855_GPI(11)) << 1;
214 static struct dcon_platform_data dcon_pdata_xo_1_5 = {
215 .init = dcon_init_xo_1_5,
216 .bus_stabilize_wiggle = dcon_wiggle_xo_1_5,
217 .set_dconload = dcon_set_dconload_xo_1_5,
218 .read_status = dcon_read_status_xo_1_5,