aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/macintosh/smu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/macintosh/smu.c')
-rw-r--r--drivers/macintosh/smu.c174
1 files changed, 168 insertions, 6 deletions
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index 34f3c7e2d832..e8378274d710 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -47,13 +47,13 @@
47#include <asm/uaccess.h> 47#include <asm/uaccess.h>
48#include <asm/of_device.h> 48#include <asm/of_device.h>
49 49
50#define VERSION "0.6" 50#define VERSION "0.7"
51#define AUTHOR "(c) 2005 Benjamin Herrenschmidt, IBM Corp." 51#define AUTHOR "(c) 2005 Benjamin Herrenschmidt, IBM Corp."
52 52
53#undef DEBUG_SMU 53#undef DEBUG_SMU
54 54
55#ifdef DEBUG_SMU 55#ifdef DEBUG_SMU
56#define DPRINTK(fmt, args...) do { printk(KERN_DEBUG fmt , ##args); } while (0) 56#define DPRINTK(fmt, args...) do { udbg_printf(KERN_DEBUG fmt , ##args); } while (0)
57#else 57#else
58#define DPRINTK(fmt, args...) do { } while (0) 58#define DPRINTK(fmt, args...) do { } while (0)
59#endif 59#endif
@@ -92,7 +92,7 @@ struct smu_device {
92 * for now, just hard code that 92 * for now, just hard code that
93 */ 93 */
94static struct smu_device *smu; 94static struct smu_device *smu;
95 95static DECLARE_MUTEX(smu_part_access);
96 96
97/* 97/*
98 * SMU driver low level stuff 98 * SMU driver low level stuff
@@ -113,9 +113,11 @@ static void smu_start_cmd(void)
113 113
114 DPRINTK("SMU: starting cmd %x, %d bytes data\n", cmd->cmd, 114 DPRINTK("SMU: starting cmd %x, %d bytes data\n", cmd->cmd,
115 cmd->data_len); 115 cmd->data_len);
116 DPRINTK("SMU: data buffer: %02x %02x %02x %02x ...\n", 116 DPRINTK("SMU: data buffer: %02x %02x %02x %02x %02x %02x %02x %02x\n",
117 ((u8 *)cmd->data_buf)[0], ((u8 *)cmd->data_buf)[1], 117 ((u8 *)cmd->data_buf)[0], ((u8 *)cmd->data_buf)[1],
118 ((u8 *)cmd->data_buf)[2], ((u8 *)cmd->data_buf)[3]); 118 ((u8 *)cmd->data_buf)[2], ((u8 *)cmd->data_buf)[3],
119 ((u8 *)cmd->data_buf)[4], ((u8 *)cmd->data_buf)[5],
120 ((u8 *)cmd->data_buf)[6], ((u8 *)cmd->data_buf)[7]);
119 121
120 /* Fill the SMU command buffer */ 122 /* Fill the SMU command buffer */
121 smu->cmd_buf->cmd = cmd->cmd; 123 smu->cmd_buf->cmd = cmd->cmd;
@@ -440,7 +442,7 @@ int smu_present(void)
440EXPORT_SYMBOL(smu_present); 442EXPORT_SYMBOL(smu_present);
441 443
442 444
443int smu_init (void) 445int __init smu_init (void)
444{ 446{
445 struct device_node *np; 447 struct device_node *np;
446 u32 *data; 448 u32 *data;
@@ -588,6 +590,8 @@ static void smu_expose_childs(void *unused)
588 sprintf(name, "smu-i2c-%02x", *reg); 590 sprintf(name, "smu-i2c-%02x", *reg);
589 of_platform_device_create(np, name, &smu->of_dev->dev); 591 of_platform_device_create(np, name, &smu->of_dev->dev);
590 } 592 }
593 if (device_is_compatible(np, "smu-sensors"))
594 of_platform_device_create(np, "smu-sensors", &smu->of_dev->dev);
591 } 595 }
592 596
593} 597}
@@ -845,6 +849,156 @@ int smu_queue_i2c(struct smu_i2c_cmd *cmd)
845 return 0; 849 return 0;
846} 850}
847 851
852/*
853 * Handling of "partitions"
854 */
855
856static int smu_read_datablock(u8 *dest, unsigned int addr, unsigned int len)
857{
858 DECLARE_COMPLETION(comp);
859 unsigned int chunk;
860 struct smu_cmd cmd;
861 int rc;
862 u8 params[8];
863
864 /* We currently use a chunk size of 0xe. We could check the
865 * SMU firmware version and use bigger sizes though
866 */
867 chunk = 0xe;
868
869 while (len) {
870 unsigned int clen = min(len, chunk);
871
872 cmd.cmd = SMU_CMD_MISC_ee_COMMAND;
873 cmd.data_len = 7;
874 cmd.data_buf = params;
875 cmd.reply_len = chunk;
876 cmd.reply_buf = dest;
877 cmd.done = smu_done_complete;
878 cmd.misc = &comp;
879 params[0] = SMU_CMD_MISC_ee_GET_DATABLOCK_REC;
880 params[1] = 0x4;
881 *((u32 *)&params[2]) = addr;
882 params[6] = clen;
883
884 rc = smu_queue_cmd(&cmd);
885 if (rc)
886 return rc;
887 wait_for_completion(&comp);
888 if (cmd.status != 0)
889 return rc;
890 if (cmd.reply_len != clen) {
891 printk(KERN_DEBUG "SMU: short read in "
892 "smu_read_datablock, got: %d, want: %d\n",
893 cmd.reply_len, clen);
894 return -EIO;
895 }
896 len -= clen;
897 addr += clen;
898 dest += clen;
899 }
900 return 0;
901}
902
903static struct smu_sdbp_header *smu_create_sdb_partition(int id)
904{
905 DECLARE_COMPLETION(comp);
906 struct smu_simple_cmd cmd;
907 unsigned int addr, len, tlen;
908 struct smu_sdbp_header *hdr;
909 struct property *prop;
910
911 /* First query the partition info */
912 smu_queue_simple(&cmd, SMU_CMD_PARTITION_COMMAND, 2,
913 smu_done_complete, &comp,
914 SMU_CMD_PARTITION_LATEST, id);
915 wait_for_completion(&comp);
916
917 /* Partition doesn't exist (or other error) */
918 if (cmd.cmd.status != 0 || cmd.cmd.reply_len != 6)
919 return NULL;
920
921 /* Fetch address and length from reply */
922 addr = *((u16 *)cmd.buffer);
923 len = cmd.buffer[3] << 2;
924 /* Calucluate total length to allocate, including the 17 bytes
925 * for "sdb-partition-XX" that we append at the end of the buffer
926 */
927 tlen = sizeof(struct property) + len + 18;
928
929 prop = kcalloc(tlen, 1, GFP_KERNEL);
930 if (prop == NULL)
931 return NULL;
932 hdr = (struct smu_sdbp_header *)(prop + 1);
933 prop->name = ((char *)prop) + tlen - 18;
934 sprintf(prop->name, "sdb-partition-%02x", id);
935 prop->length = len;
936 prop->value = (unsigned char *)hdr;
937 prop->next = NULL;
938
939 /* Read the datablock */
940 if (smu_read_datablock((u8 *)hdr, addr, len)) {
941 printk(KERN_DEBUG "SMU: datablock read failed while reading "
942 "partition %02x !\n", id);
943 goto failure;
944 }
945
946 /* Got it, check a few things and create the property */
947 if (hdr->id != id) {
948 printk(KERN_DEBUG "SMU: Reading partition %02x and got "
949 "%02x !\n", id, hdr->id);
950 goto failure;
951 }
952 if (prom_add_property(smu->of_node, prop)) {
953 printk(KERN_DEBUG "SMU: Failed creating sdb-partition-%02x "
954 "property !\n", id);
955 goto failure;
956 }
957
958 return hdr;
959 failure:
960 kfree(prop);
961 return NULL;
962}
963
964/* Note: Only allowed to return error code in pointers (using ERR_PTR)
965 * when interruptible is 1
966 */
967struct smu_sdbp_header *__smu_get_sdb_partition(int id, unsigned int *size,
968 int interruptible)
969{
970 char pname[32];
971 struct smu_sdbp_header *part;
972
973 if (!smu)
974 return NULL;
975
976 sprintf(pname, "sdb-partition-%02x", id);
977
978 if (interruptible) {
979 int rc;
980 rc = down_interruptible(&smu_part_access);
981 if (rc)
982 return ERR_PTR(rc);
983 } else
984 down(&smu_part_access);
985
986 part = (struct smu_sdbp_header *)get_property(smu->of_node,
987 pname, size);
988 if (part == NULL) {
989 part = smu_create_sdb_partition(id);
990 if (part != NULL && size)
991 *size = part->len << 2;
992 }
993 up(&smu_part_access);
994 return part;
995}
996
997struct smu_sdbp_header *smu_get_sdb_partition(int id, unsigned int *size)
998{
999 return __smu_get_sdb_partition(id, size, 0);
1000}
1001EXPORT_SYMBOL(smu_get_sdb_partition);
848 1002
849 1003
850/* 1004/*
@@ -918,6 +1072,14 @@ static ssize_t smu_write(struct file *file, const char __user *buf,
918 else if (hdr.cmdtype == SMU_CMDTYPE_WANTS_EVENTS) { 1072 else if (hdr.cmdtype == SMU_CMDTYPE_WANTS_EVENTS) {
919 pp->mode = smu_file_events; 1073 pp->mode = smu_file_events;
920 return 0; 1074 return 0;
1075 } else if (hdr.cmdtype == SMU_CMDTYPE_GET_PARTITION) {
1076 struct smu_sdbp_header *part;
1077 part = __smu_get_sdb_partition(hdr.cmd, NULL, 1);
1078 if (part == NULL)
1079 return -EINVAL;
1080 else if (IS_ERR(part))
1081 return PTR_ERR(part);
1082 return 0;
921 } else if (hdr.cmdtype != SMU_CMDTYPE_SMU) 1083 } else if (hdr.cmdtype != SMU_CMDTYPE_SMU)
922 return -EINVAL; 1084 return -EINVAL;
923 else if (pp->mode != smu_file_commands) 1085 else if (pp->mode != smu_file_commands)