This is a diff for drivers/char/drm to make r128 use userland-loadable firmware. It's completely untested (since I don't *have* an r128, I don't see any way to test it), but I bet it'll work; the firmware loading interface seems remarkably easy to use.
Following that (in the form of a diff) is the short program I used to create a microcode file which could be shipped as the file /usr/lib/hotplug/r128_cce_microcode (I left it in this form to avoid problems with attaching binaries.) Similar (nearly identical) changes could be made to the radeon driver in the same directory, and I'll be happy to make them if needed. This could probably be improved by someone with a better sense of the right way to deal with the stupid endianness issues; I went with the simplistic "pick an endianness" choice. Please do tell me if there's a major problem with this that I can fix. The one which worries me the most is the possibility that the firmware loading is not done in user context, or that it's done when holding a lock which means that it mustn't sleep. (Request_firmware obviously sleeps, since it calls into userland.) After spending something like 6 hours trawling through the code backwards and forwards, I decided it *probably* wasn't, but I wasn't sure. There's also a faint possibility of deadlock if the userland process which is supposed to load the firmware waits for the DRM module in order to use the screen; this shouldn't happen because it's a background daemon (hotplug), and the standard script only calls "cat [file] > sysfs/[phony file]". If either of these is a problem, the firmware may have to be loaded and cached in memory at module load time in the module load routine, and only disposed of at module unload. I couldn't actually find those routines, which is one reason I didn't do that. ;-) The other is that it seems like it's a waste of memory to do anything other than retrieving it when it's needed and disposing of it afterwards. Of course, given my lack of DRM experience, there could be any number of other gotchas. :-P My changes are GPL licensed (of course). (Incidentally, what *is* this microcode? It looks like it's actually two separate sets of code interleaved.) Please email me with comments/requests, as I'm not subscribed. --- r128_cce.c 2003-09-28 00:44:12.000000000 -0400 +++ r128_cce.c.new 2004-04-12 19:32:39.000000000 -0400 @@ -3,6 +3,7 @@ * * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * Portions copyright 2003 Nathanael Nerode. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -28,6 +29,7 @@ * Gareth Hughes <[EMAIL PROTECTED]> */ +#include <linux/firmware.h> #include "r128.h" #include "drmP.h" #include "drm.h" @@ -36,51 +38,6 @@ #define R128_FIFO_DEBUG 0 -/* CCE microcode (from ATI) */ -static u32 r128_cce_microcode[] = { - 0, 276838400, 0, 268449792, 2, 142, 2, 145, 0, 1076765731, 0, - 1617039951, 0, 774592877, 0, 1987540286, 0, 2307490946U, 0, - 599558925, 0, 589505315, 0, 596487092, 0, 589505315, 1, - 11544576, 1, 206848, 1, 311296, 1, 198656, 2, 912273422, 11, - 262144, 0, 0, 1, 33559837, 1, 7438, 1, 14809, 1, 6615, 12, 28, - 1, 6614, 12, 28, 2, 23, 11, 18874368, 0, 16790922, 1, 409600, 9, - 30, 1, 147854772, 16, 420483072, 3, 8192, 0, 10240, 1, 198656, - 1, 15630, 1, 51200, 10, 34858, 9, 42, 1, 33559823, 2, 10276, 1, - 15717, 1, 15718, 2, 43, 1, 15936948, 1, 570480831, 1, 14715071, - 12, 322123831, 1, 33953125, 12, 55, 1, 33559908, 1, 15718, 2, - 46, 4, 2099258, 1, 526336, 1, 442623, 4, 4194365, 1, 509952, 1, - 459007, 3, 0, 12, 92, 2, 46, 12, 176, 1, 15734, 1, 206848, 1, - 18432, 1, 133120, 1, 100670734, 1, 149504, 1, 165888, 1, - 15975928, 1, 1048576, 6, 3145806, 1, 15715, 16, 2150645232U, 2, - 268449859, 2, 10307, 12, 176, 1, 15734, 1, 15735, 1, 15630, 1, - 15631, 1, 5253120, 6, 3145810, 16, 2150645232U, 1, 15864, 2, 82, - 1, 343310, 1, 1064207, 2, 3145813, 1, 15728, 1, 7817, 1, 15729, - 3, 15730, 12, 92, 2, 98, 1, 16168, 1, 16167, 1, 16002, 1, 16008, - 1, 15974, 1, 15975, 1, 15990, 1, 15976, 1, 15977, 1, 15980, 0, - 15981, 1, 10240, 1, 5253120, 1, 15720, 1, 198656, 6, 110, 1, - 180224, 1, 103824738, 2, 112, 2, 3145839, 0, 536885440, 1, - 114880, 14, 125, 12, 206975, 1, 33559995, 12, 198784, 0, - 33570236, 1, 15803, 0, 15804, 3, 294912, 1, 294912, 3, 442370, - 1, 11544576, 0, 811612160, 1, 12593152, 1, 11536384, 1, - 14024704, 7, 310382726, 0, 10240, 1, 14796, 1, 14797, 1, 14793, - 1, 14794, 0, 14795, 1, 268679168, 1, 9437184, 1, 268449792, 1, - 198656, 1, 9452827, 1, 1075854602, 1, 1075854603, 1, 557056, 1, - 114880, 14, 159, 12, 198784, 1, 1109409213, 12, 198783, 1, - 1107312059, 12, 198784, 1, 1109409212, 2, 162, 1, 1075854781, 1, - 1073757627, 1, 1075854780, 1, 540672, 1, 10485760, 6, 3145894, - 16, 274741248, 9, 168, 3, 4194304, 3, 4209949, 0, 0, 0, 256, 14, - 174, 1, 114857, 1, 33560007, 12, 176, 0, 10240, 1, 114858, 1, - 33560018, 1, 114857, 3, 33560007, 1, 16008, 1, 114874, 1, - 33560360, 1, 114875, 1, 33560154, 0, 15963, 0, 256, 0, 4096, 1, - 409611, 9, 188, 0, 10240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - int R128_READ_PLL(drm_device_t *dev, int addr) { drm_r128_private_t *dev_priv = dev->dev_private; @@ -176,21 +133,50 @@ */ /* Load the microcode for the CCE */ -static void r128_cce_load_microcode( drm_r128_private_t *dev_priv ) +static void r128_cce_load_microcode( drm_device_t *dev, + drm_r128_private_t *dev_priv ) { int i; + const struct firmware *fw_entry = NULL; + + if ( request_firmware(&fw_entry, "r128_cce_microcode", &dev) != 0 ) { + printk(KERN_ALERT + "%s: Firmware \"r128_cce_microcode\" not available.\n", + dev->name); + return; + } DRM_DEBUG( "\n" ); r128_do_wait_for_idle( dev_priv ); R128_WRITE( R128_PM4_MICROCODE_ADDR, 0 ); + + /* Assumes 256 x 2 x 32 bits of data */ + if (fw_entry->size != 256 * 4 * 2) { + printk(KERN_ALERT + "%s: Firmware \"r128_cce_microcode\" wrong size!\n", + dev->name); + return; + } + for ( i = 0 ; i < 256 ; i++ ) { + /* fw_entry->data is a char[], but we want a u32[] (sigh). + We simply assume big-endian byte order for now. */ R128_WRITE( R128_PM4_MICROCODE_DATAH, - r128_cce_microcode[i * 2] ); + ( (u32) fw_entry->data[i * 8] << 24) + + ( (u32) fw_entry->data[i * 8 + 1] << 16) + + ( (u32) fw_entry->data[i * 8 + 2] << 8) + + ( (u32) fw_entry->data[i * 8 + 3]) + ); R128_WRITE( R128_PM4_MICROCODE_DATAL, - r128_cce_microcode[i * 2 + 1] ); + ( (u32) fw_entry->data[i * 8 + 4] << 24) + + ( (u32) fw_entry->data[i * 8 + 5] << 16) + + ( (u32) fw_entry->data[i * 8 + 6] << 8) + + ( (u32) fw_entry->data[i * 8 + 7]) + ); } + release_firmware(fw_entry); } /* Flush any pending commands to the CCE. This should only be used just @@ -603,7 +589,7 @@ #endif r128_cce_init_ring_buffer( dev, dev_priv ); - r128_cce_load_microcode( dev_priv ); + r128_cce_load_microcode( dev, dev_priv ); dev->dev_private = (void *)dev_priv; --- /dev/null 2004-02-24 18:25:18.000000000 -0500 +++ write_r128_microcode.c 2004-04-12 18:59:00.000000000 -0400 @@ -0,0 +1,67 @@ +#include <stdio.h> + +/* CCE microcode (from ATI) */ +static unsigned int r128_cce_microcode[] = { + 0, 276838400, 0, 268449792, 2, 142, 2, 145, 0, 1076765731, 0, + 1617039951, 0, 774592877, 0, 1987540286, 0, 2307490946U, 0, + 599558925, 0, 589505315, 0, 596487092, 0, 589505315, 1, + 11544576, 1, 206848, 1, 311296, 1, 198656, 2, 912273422, 11, + 262144, 0, 0, 1, 33559837, 1, 7438, 1, 14809, 1, 6615, 12, 28, + 1, 6614, 12, 28, 2, 23, 11, 18874368, 0, 16790922, 1, 409600, 9, + 30, 1, 147854772, 16, 420483072, 3, 8192, 0, 10240, 1, 198656, + 1, 15630, 1, 51200, 10, 34858, 9, 42, 1, 33559823, 2, 10276, 1, + 15717, 1, 15718, 2, 43, 1, 15936948, 1, 570480831, 1, 14715071, + 12, 322123831, 1, 33953125, 12, 55, 1, 33559908, 1, 15718, 2, + 46, 4, 2099258, 1, 526336, 1, 442623, 4, 4194365, 1, 509952, 1, + 459007, 3, 0, 12, 92, 2, 46, 12, 176, 1, 15734, 1, 206848, 1, + 18432, 1, 133120, 1, 100670734, 1, 149504, 1, 165888, 1, + 15975928, 1, 1048576, 6, 3145806, 1, 15715, 16, 2150645232U, 2, + 268449859, 2, 10307, 12, 176, 1, 15734, 1, 15735, 1, 15630, 1, + 15631, 1, 5253120, 6, 3145810, 16, 2150645232U, 1, 15864, 2, 82, + 1, 343310, 1, 1064207, 2, 3145813, 1, 15728, 1, 7817, 1, 15729, + 3, 15730, 12, 92, 2, 98, 1, 16168, 1, 16167, 1, 16002, 1, 16008, + 1, 15974, 1, 15975, 1, 15990, 1, 15976, 1, 15977, 1, 15980, 0, + 15981, 1, 10240, 1, 5253120, 1, 15720, 1, 198656, 6, 110, 1, + 180224, 1, 103824738, 2, 112, 2, 3145839, 0, 536885440, 1, + 114880, 14, 125, 12, 206975, 1, 33559995, 12, 198784, 0, + 33570236, 1, 15803, 0, 15804, 3, 294912, 1, 294912, 3, 442370, + 1, 11544576, 0, 811612160, 1, 12593152, 1, 11536384, 1, + 14024704, 7, 310382726, 0, 10240, 1, 14796, 1, 14797, 1, 14793, + 1, 14794, 0, 14795, 1, 268679168, 1, 9437184, 1, 268449792, 1, + 198656, 1, 9452827, 1, 1075854602, 1, 1075854603, 1, 557056, 1, + 114880, 14, 159, 12, 198784, 1, 1109409213, 12, 198783, 1, + 1107312059, 12, 198784, 1, 1109409212, 2, 162, 1, 1075854781, 1, + 1073757627, 1, 1075854780, 1, 540672, 1, 10485760, 6, 3145894, + 16, 274741248, 9, 168, 3, 4194304, 3, 4209949, 0, 0, 0, 256, 14, + 174, 1, 114857, 1, 33560007, 12, 176, 0, 10240, 1, 114858, 1, + 33560018, 1, 114857, 3, 33560007, 1, 16008, 1, 114874, 1, + 33560360, 1, 114875, 1, 33560154, 0, 15963, 0, 256, 0, 4096, 1, + 409611, 9, 188, 0, 10240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +int main(int argc, const char** argv) { + int i; + unsigned char a,b,c,d; + FILE *f; + + f=fopen("r128_cce_microcode","w"); + for (i=0; i < 512; i++) { + /* Unwrap into big-endian order. */ + a = r128_cce_microcode[i] >> 24 ; + b = (r128_cce_microcode[i] >> 16) & 0xFF; + c = (r128_cce_microcode[i] >> 8) & 0xFF; + d = (r128_cce_microcode[i]) & 0xFF; + fputc(a, f); + fputc(b, f); + fputc(c, f); + fputc(d, f); + } + fclose(f); +} -- There are none so blind as those who will not see. ------------------------------------------------------- This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click -- _______________________________________________ Dri-devel mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/dri-devel