ppc32: Update PowerMac i2c management

Create a low-level synchronous implementation suitable for use
by the early boot platform code or other places where the
asynchronous driver isn't useable. This also exports the locks
used by the real driver to avoid collisions.
Use this new implementation to properly setup the clock chip
at boot on Apple latest laptops
parent e37fe183
......@@ -17,7 +17,8 @@ ifeq ($(CONFIG_APUS),y)
obj-$(CONFIG_PCI) += apus_pci.o
endif
obj-$(CONFIG_PPC_PMAC) += pmac_pic.o pmac_setup.o pmac_time.o \
pmac_feature.o pmac_pci.o pmac_sleep.o
pmac_feature.o pmac_pci.o pmac_sleep.o \
pmac_low_i2c.o
obj-$(CONFIG_PPC_CHRP) += chrp_setup.o chrp_time.o chrp_pci.o
obj-$(CONFIG_PPC_PREP) += prep_pci.o prep_time.o prep_setup.o
ifeq ($(CONFIG_PPC_PMAC),y)
......
......@@ -41,6 +41,7 @@
#include <asm/pmac_feature.h>
#include <asm/dbdma.h>
#include <asm/pci-bridge.h>
#include <asm/pmac_low_i2c.h>
#undef DEBUG_FEATURE
......@@ -2601,6 +2602,99 @@ set_initial_features(void)
MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
}
/* Hack for bumping clock speed on the new PowerBooks and the
* iBook G4. This implements the "platform-do-clockspreading" OF
* property. For safety, we also check the product ID in the
* device-tree to make reasonably sure we won't set wrong values
* in the clock chip.
*
* Of course, ultimately, we have to implement a real parser for
* the platform-do-* stuff...
*/
while (machine_is_compatible("PowerBook5,2") ||
machine_is_compatible("PowerBook5,3") ||
machine_is_compatible("PowerBook6,2") ||
machine_is_compatible("PowerBook6,3")) {
struct device_node *ui2c = of_find_node_by_type(NULL, "i2c");
struct device_node *dt = of_find_node_by_name(NULL, "device-tree");
u8 buffer[9];
u32 *productID;
int i, rc, changed = 0;
if (dt == NULL)
break;
productID = (u32 *)get_property(dt, "pid#", NULL);
if (productID == NULL)
break;
while(ui2c) {
struct device_node *p = of_get_parent(ui2c);
if (p && !strcmp(p->name, "uni-n"))
break;
ui2c = of_find_node_by_type(np, "i2c");
}
if (ui2c == NULL)
break;
DBG("Trying to bump clock speed for PID: %08x...\n", *productID);
rc = pmac_low_i2c_open(ui2c, 1);
if (rc != 0)
break;
pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
DBG("read result: %d,", rc);
if (rc != 0) {
pmac_low_i2c_close(ui2c);
break;
}
for (i=0; i<9; i++)
DBG(" %02x", buffer[i]);
DBG("\n");
switch(*productID) {
case 0x1182: /* AlBook 12" rev 2 */
case 0x1183: /* iBook G4 12" */
buffer[0] = (buffer[0] & 0x8f) | 0x70;
buffer[2] = (buffer[2] & 0x7f) | 0x00;
buffer[5] = (buffer[5] & 0x80) | 0x31;
buffer[6] = (buffer[6] & 0x40) | 0xb0;
buffer[7] = (buffer[7] & 0x00) | 0xc0;
buffer[8] = (buffer[8] & 0x00) | 0x30;
changed = 1;
break;
case 0x3142: /* AlBook 15" (ATI M10) */
case 0x3143: /* AlBook 17" (ATI M10) */
buffer[0] = (buffer[0] & 0xaf) | 0x50;
buffer[2] = (buffer[2] & 0x7f) | 0x00;
buffer[5] = (buffer[5] & 0x80) | 0x31;
buffer[6] = (buffer[6] & 0x40) | 0xb0;
buffer[7] = (buffer[7] & 0x00) | 0xd0;
buffer[8] = (buffer[8] & 0x00) | 0x30;
changed = 1;
break;
default:
DBG("i2c-hwclock: Machine model not handled\n");
break;
}
if (!changed) {
pmac_low_i2c_close(ui2c);
break;
}
pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub);
rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9);
DBG("write result: %d,", rc);
pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
DBG("read result: %d,", rc);
if (rc != 0) {
pmac_low_i2c_close(ui2c);
break;
}
for (i=0; i<9; i++)
DBG(" %02x", buffer[i]);
pmac_low_i2c_close(ui2c);
break;
}
#endif /* CONFIG_POWER4 */
/* On all machines, switch modem & serial ports off */
np = find_devices("ch-a");
......@@ -2627,6 +2721,9 @@ pmac_feature_init(void)
return;
}
/* Setup low-level i2c stuffs */
pmac_init_low_i2c();
/* Probe machine type */
if (probe_motherboard())
printk(KERN_WARNING "Unknown PowerMac !\n");
......
This diff is collapsed.
......@@ -469,10 +469,6 @@ pmac_restart(char *cmd)
struct adb_request req;
#endif /* CONFIG_ADB_CUDA */
#ifdef CONFIG_NVRAM
pmac_nvram_update();
#endif
switch (sys_ctrler) {
#ifdef CONFIG_ADB_CUDA
case SYS_CTRLER_CUDA:
......@@ -498,10 +494,6 @@ pmac_power_off(void)
struct adb_request req;
#endif /* CONFIG_ADB_CUDA */
#ifdef CONFIG_NVRAM
pmac_nvram_update();
#endif
switch (sys_ctrler) {
#ifdef CONFIG_ADB_CUDA
case SYS_CTRLER_CUDA:
......@@ -637,11 +629,6 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.get_rtc_time = pmac_get_rtc_time;
ppc_md.calibrate_decr = pmac_calibrate_decr;
#ifdef CONFIG_NVRAM
ppc_md.nvram_read_val = pmac_nvram_read_byte;
ppc_md.nvram_write_val = pmac_nvram_write_byte;
#endif
ppc_md.find_end_of_memory = pmac_find_end_of_memory;
ppc_md.feature_call = pmac_do_feature_call;
......@@ -685,6 +672,14 @@ pmac_declare_of_platform_devices(void)
break;
}
}
np = find_devices("u3");
if (np) {
for (np = np->child; np != NULL; np = np->sibling)
if (strncmp(np->name, "i2c", 3) == 0) {
of_platform_device_create(np, "u3-i2c");
break;
}
}
np = find_devices("valkyrie");
if (np)
......
This diff is collapsed.
......@@ -51,20 +51,19 @@ typedef enum {
/* Physical interface */
struct keywest_iface
{
struct device_node *node;
unsigned long base;
unsigned bsteps;
int irq;
struct semaphore sem;
spinlock_t lock;
struct keywest_chan* channels;
struct keywest_chan *channels;
unsigned chan_count;
u8 cur_mode;
char read_write;
u8* data;
u8 *data;
unsigned datalen;
int state;
int result;
int stopretry;
struct timer_list timeout_timer;
struct completion complete;
};
......@@ -98,8 +97,7 @@ static inline void __write_reg(struct keywest_iface *iface, reg_t reg, u8 val)
{
out_8(((volatile u8 *)iface->base)
+ (((unsigned)reg) << iface->bsteps), val);
(void)__read_reg(iface, reg);
udelay(10);
(void)__read_reg(iface, reg_subaddr);
}
#define write_reg(reg, val) __write_reg(iface, reg, val)
......
/*
* include/asm-ppc/pmac_low_i2c.h
*
* Copyright (C) 2003 Ben. Herrenschmidt (benh@kernel.crashing.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
*/
#ifndef __PMAC_LOW_I2C_H__
#define __PMAC_LOW_I2C_H__
/* i2c mode (based on the platform functions format) */
enum {
pmac_low_i2c_mode_dumb = 1,
pmac_low_i2c_mode_std = 2,
pmac_low_i2c_mode_stdsub = 3,
pmac_low_i2c_mode_combined = 4,
};
/* RW bit in address */
enum {
pmac_low_i2c_read = 0x01,
pmac_low_i2c_write = 0x00
};
/* Init, called early during boot */
extern void pmac_init_low_i2c(void);
/* Locking functions exposed to i2c-keywest */
int pmac_low_i2c_lock(struct device_node *np);
int pmac_low_i2c_unlock(struct device_node *np);
/* Access functions for platform code */
int pmac_low_i2c_open(struct device_node *np, int channel);
int pmac_low_i2c_close(struct device_node *np);
int pmac_low_i2c_setmode(struct device_node *np, int mode);
int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len);
#endif /* __PMAC_LOW_I2C_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment