Whoa, forgot to check in a bunch of radeon stuff

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@8435 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
shadow303 2004-07-20 02:17:39 +00:00
parent 51c74f5a0c
commit 5f6e3f515c
19 changed files with 3160 additions and 956 deletions

View File

@ -0,0 +1,786 @@
#ifndef _CPMICROCODE_H
#define _CPMICROCODE_H
// CP microcode (from ATI)
// if you take a look at the hex-dump
// you find some hidden message ;)
static const uint32 radeon_cp_microcode[][2] = {
{ 0x21007000, 0000000000 },
{ 0x20007000, 0000000000 },
{ 0x000000b4, 0x00000004 },
{ 0x000000b8, 0x00000004 },
{ 0x6f5b4d4c, 0000000000 },
{ 0x4c4c427f, 0000000000 },
{ 0x5b568a92, 0000000000 },
{ 0x4ca09c6d, 0000000000 },
{ 0xad4c4c4c, 0000000000 },
{ 0x4ce1af3d, 0000000000 },
{ 0xd8afafaf, 0000000000 },
{ 0xd64c4cdc, 0000000000 },
{ 0x4cd10d10, 0000000000 },
{ 0x000f0000, 0x00000016 },
{ 0x362f242d, 0000000000 },
{ 0x00000012, 0x00000004 },
{ 0x000f0000, 0x00000016 },
{ 0x362f282d, 0000000000 },
{ 0x000380e7, 0x00000002 },
{ 0x04002c97, 0x00000002 },
{ 0x000f0001, 0x00000016 },
{ 0x333a3730, 0000000000 },
{ 0x000077ef, 0x00000002 },
{ 0x00061000, 0x00000002 },
{ 0x00000021, 0x0000001a },
{ 0x00004000, 0x0000001e },
{ 0x00061000, 0x00000002 },
{ 0x00000021, 0x0000001a },
{ 0x00004000, 0x0000001e },
{ 0x00061000, 0x00000002 },
{ 0x00000021, 0x0000001a },
{ 0x00004000, 0x0000001e },
{ 0x00000017, 0x00000004 },
{ 0x0003802b, 0x00000002 },
{ 0x040067e0, 0x00000002 },
{ 0x00000017, 0x00000004 },
{ 0x000077e0, 0x00000002 },
{ 0x00065000, 0x00000002 },
{ 0x000037e1, 0x00000002 },
{ 0x040067e1, 0x00000006 },
{ 0x000077e0, 0x00000002 },
{ 0x000077e1, 0x00000002 },
{ 0x000077e1, 0x00000006 },
{ 0xffffffff, 0000000000 },
{ 0x10000000, 0000000000 },
{ 0x0003802b, 0x00000002 },
{ 0x040067e0, 0x00000006 },
{ 0x00007675, 0x00000002 },
{ 0x00007676, 0x00000002 },
{ 0x00007677, 0x00000002 },
{ 0x00007678, 0x00000006 },
{ 0x0003802c, 0x00000002 },
{ 0x04002676, 0x00000002 },
{ 0x00007677, 0x00000002 },
{ 0x00007678, 0x00000006 },
{ 0x0000002f, 0x00000018 },
{ 0x0000002f, 0x00000018 },
{ 0000000000, 0x00000006 },
{ 0x00000030, 0x00000018 },
{ 0x00000030, 0x00000018 },
{ 0000000000, 0x00000006 },
{ 0x01605000, 0x00000002 },
{ 0x00065000, 0x00000002 },
{ 0x00098000, 0x00000002 },
{ 0x00061000, 0x00000002 },
{ 0x64c0603e, 0x00000004 },
{ 0x000380e6, 0x00000002 },
{ 0x040025c5, 0x00000002 },
{ 0x00080000, 0x00000016 },
{ 0000000000, 0000000000 },
{ 0x0400251d, 0x00000002 },
{ 0x00007580, 0x00000002 },
{ 0x00067581, 0x00000002 },
{ 0x04002580, 0x00000002 },
{ 0x00067581, 0x00000002 },
{ 0x00000049, 0x00000004 },
{ 0x00005000, 0000000000 },
{ 0x000380e6, 0x00000002 },
{ 0x040025c5, 0x00000002 },
{ 0x00061000, 0x00000002 },
{ 0x0000750e, 0x00000002 },
{ 0x00019000, 0x00000002 },
{ 0x00011055, 0x00000014 },
{ 0x00000055, 0x00000012 },
{ 0x0400250f, 0x00000002 },
{ 0x0000504f, 0x00000004 },
{ 0x000380e6, 0x00000002 },
{ 0x040025c5, 0x00000002 },
{ 0x00007565, 0x00000002 },
{ 0x00007566, 0x00000002 },
{ 0x00000058, 0x00000004 },
{ 0x000380e6, 0x00000002 },
{ 0x040025c5, 0x00000002 },
{ 0x01e655b4, 0x00000002 },
{ 0x4401b0e4, 0x00000002 },
{ 0x01c110e4, 0x00000002 },
{ 0x26667066, 0x00000018 },
{ 0x040c2565, 0x00000002 },
{ 0x00000066, 0x00000018 },
{ 0x04002564, 0x00000002 },
{ 0x00007566, 0x00000002 },
{ 0x0000005d, 0x00000004 },
{ 0x00401069, 0x00000008 },
{ 0x00101000, 0x00000002 },
{ 0x000d80ff, 0x00000002 },
{ 0x0080006c, 0x00000008 },
{ 0x000f9000, 0x00000002 },
{ 0x000e00ff, 0x00000002 },
{ 0000000000, 0x00000006 },
{ 0x0000008f, 0x00000018 },
{ 0x0000005b, 0x00000004 },
{ 0x000380e6, 0x00000002 },
{ 0x040025c5, 0x00000002 },
{ 0x00007576, 0x00000002 },
{ 0x00065000, 0x00000002 },
{ 0x00009000, 0x00000002 },
{ 0x00041000, 0x00000002 },
{ 0x0c00350e, 0x00000002 },
{ 0x00049000, 0x00000002 },
{ 0x00051000, 0x00000002 },
{ 0x01e785f8, 0x00000002 },
{ 0x00200000, 0x00000002 },
{ 0x0060007e, 0x0000000c },
{ 0x00007563, 0x00000002 },
{ 0x006075f0, 0x00000021 },
{ 0x20007073, 0x00000004 },
{ 0x00005073, 0x00000004 },
{ 0x000380e6, 0x00000002 },
{ 0x040025c5, 0x00000002 },
{ 0x00007576, 0x00000002 },
{ 0x00007577, 0x00000002 },
{ 0x0000750e, 0x00000002 },
{ 0x0000750f, 0x00000002 },
{ 0x00a05000, 0x00000002 },
{ 0x00600083, 0x0000000c },
{ 0x006075f0, 0x00000021 },
{ 0x000075f8, 0x00000002 },
{ 0x00000083, 0x00000004 },
{ 0x000a750e, 0x00000002 },
{ 0x000380e6, 0x00000002 },
{ 0x040025c5, 0x00000002 },
{ 0x0020750f, 0x00000002 },
{ 0x00600086, 0x00000004 },
{ 0x00007570, 0x00000002 },
{ 0x00007571, 0x00000002 },
{ 0x00007572, 0x00000006 },
{ 0x000380e6, 0x00000002 },
{ 0x040025c5, 0x00000002 },
{ 0x00005000, 0x00000002 },
{ 0x00a05000, 0x00000002 },
{ 0x00007568, 0x00000002 },
{ 0x00061000, 0x00000002 },
{ 0x00000095, 0x0000000c },
{ 0x00058000, 0x00000002 },
{ 0x0c607562, 0x00000002 },
{ 0x00000097, 0x00000004 },
{ 0x000380e6, 0x00000002 },
{ 0x040025c5, 0x00000002 },
{ 0x00600096, 0x00000004 },
{ 0x400070e5, 0000000000 },
{ 0x000380e6, 0x00000002 },
{ 0x040025c5, 0x00000002 },
{ 0x000380e5, 0x00000002 },
{ 0x000000a8, 0x0000001c },
{ 0x000650aa, 0x00000018 },
{ 0x040025bb, 0x00000002 },
{ 0x000610ab, 0x00000018 },
{ 0x040075bc, 0000000000 },
{ 0x000075bb, 0x00000002 },
{ 0x000075bc, 0000000000 },
{ 0x00090000, 0x00000006 },
{ 0x00090000, 0x00000002 },
{ 0x000d8002, 0x00000006 },
{ 0x00007832, 0x00000002 },
{ 0x00005000, 0x00000002 },
{ 0x000380e7, 0x00000002 },
{ 0x04002c97, 0x00000002 },
{ 0x00007820, 0x00000002 },
{ 0x00007821, 0x00000002 },
{ 0x00007800, 0000000000 },
{ 0x01200000, 0x00000002 },
{ 0x20077000, 0x00000002 },
{ 0x01200000, 0x00000002 },
{ 0x20007000, 0x00000002 },
{ 0x00061000, 0x00000002 },
{ 0x0120751b, 0x00000002 },
{ 0x8040750a, 0x00000002 },
{ 0x8040750b, 0x00000002 },
{ 0x00110000, 0x00000002 },
{ 0x000380e5, 0x00000002 },
{ 0x000000c6, 0x0000001c },
{ 0x000610ab, 0x00000018 },
{ 0x844075bd, 0x00000002 },
{ 0x000610aa, 0x00000018 },
{ 0x840075bb, 0x00000002 },
{ 0x000610ab, 0x00000018 },
{ 0x844075bc, 0x00000002 },
{ 0x000000c9, 0x00000004 },
{ 0x804075bd, 0x00000002 },
{ 0x800075bb, 0x00000002 },
{ 0x804075bc, 0x00000002 },
{ 0x00108000, 0x00000002 },
{ 0x01400000, 0x00000002 },
{ 0x006000cd, 0x0000000c },
{ 0x20c07000, 0x00000020 },
{ 0x000000cf, 0x00000012 },
{ 0x00800000, 0x00000006 },
{ 0x0080751d, 0x00000006 },
{ 0000000000, 0000000000 },
{ 0x0000775c, 0x00000002 },
{ 0x00a05000, 0x00000002 },
{ 0x00661000, 0x00000002 },
{ 0x0460275d, 0x00000020 },
{ 0x00004000, 0000000000 },
{ 0x01e00830, 0x00000002 },
{ 0x21007000, 0000000000 },
{ 0x6464614d, 0000000000 },
{ 0x69687420, 0000000000 },
{ 0x00000073, 0000000000 },
{ 0000000000, 0000000000 },
{ 0x00005000, 0x00000002 },
{ 0x000380d0, 0x00000002 },
{ 0x040025e0, 0x00000002 },
{ 0x000075e1, 0000000000 },
{ 0x00000001, 0000000000 },
{ 0x000380e0, 0x00000002 },
{ 0x04002394, 0x00000002 },
{ 0x00005000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0x00000008, 0000000000 },
{ 0x00000004, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
};
// special r200 microcode
static const uint32 r200_cp_microcode[][2] = {
{ 0x21007000, 0000000000 },
{ 0x20007000, 0000000000 },
{ 0x000000ab, 0x00000004 },
{ 0x000000af, 0x00000004 },
{ 0x66544a49, 0000000000 },
{ 0x49494174, 0000000000 },
{ 0x54517d83, 0000000000 },
{ 0x498d8b64, 0000000000 },
{ 0x49494949, 0000000000 },
{ 0x49da493c, 0000000000 },
{ 0x49989898, 0000000000 },
{ 0xd34949d5, 0000000000 },
{ 0x9dc90e11, 0000000000 },
{ 0xce9b9b9b, 0000000000 },
{ 0x000f0000, 0x00000016 },
{ 0x352e232c, 0000000000 },
{ 0x00000013, 0x00000004 },
{ 0x000f0000, 0x00000016 },
{ 0x352e272c, 0000000000 },
{ 0x000f0001, 0x00000016 },
{ 0x3239362f, 0000000000 },
{ 0x000077ef, 0x00000002 },
{ 0x00061000, 0x00000002 },
{ 0x00000020, 0x0000001a },
{ 0x00004000, 0x0000001e },
{ 0x00061000, 0x00000002 },
{ 0x00000020, 0x0000001a },
{ 0x00004000, 0x0000001e },
{ 0x00061000, 0x00000002 },
{ 0x00000020, 0x0000001a },
{ 0x00004000, 0x0000001e },
{ 0x00000016, 0x00000004 },
{ 0x0003802a, 0x00000002 },
{ 0x040067e0, 0x00000002 },
{ 0x00000016, 0x00000004 },
{ 0x000077e0, 0x00000002 },
{ 0x00065000, 0x00000002 },
{ 0x000037e1, 0x00000002 },
{ 0x040067e1, 0x00000006 },
{ 0x000077e0, 0x00000002 },
{ 0x000077e1, 0x00000002 },
{ 0x000077e1, 0x00000006 },
{ 0xffffffff, 0000000000 },
{ 0x10000000, 0000000000 },
{ 0x0003802a, 0x00000002 },
{ 0x040067e0, 0x00000006 },
{ 0x00007675, 0x00000002 },
{ 0x00007676, 0x00000002 },
{ 0x00007677, 0x00000002 },
{ 0x00007678, 0x00000006 },
{ 0x0003802b, 0x00000002 },
{ 0x04002676, 0x00000002 },
{ 0x00007677, 0x00000002 },
{ 0x00007678, 0x00000006 },
{ 0x0000002e, 0x00000018 },
{ 0x0000002e, 0x00000018 },
{ 0000000000, 0x00000006 },
{ 0x0000002f, 0x00000018 },
{ 0x0000002f, 0x00000018 },
{ 0000000000, 0x00000006 },
{ 0x01605000, 0x00000002 },
{ 0x00065000, 0x00000002 },
{ 0x00098000, 0x00000002 },
{ 0x00061000, 0x00000002 },
{ 0x64c0603d, 0x00000004 },
{ 0x00080000, 0x00000016 },
{ 0000000000, 0000000000 },
{ 0x0400251d, 0x00000002 },
{ 0x00007580, 0x00000002 },
{ 0x00067581, 0x00000002 },
{ 0x04002580, 0x00000002 },
{ 0x00067581, 0x00000002 },
{ 0x00000046, 0x00000004 },
{ 0x00005000, 0000000000 },
{ 0x00061000, 0x00000002 },
{ 0x0000750e, 0x00000002 },
{ 0x00019000, 0x00000002 },
{ 0x00011055, 0x00000014 },
{ 0x00000055, 0x00000012 },
{ 0x0400250f, 0x00000002 },
{ 0x0000504a, 0x00000004 },
{ 0x00007565, 0x00000002 },
{ 0x00007566, 0x00000002 },
{ 0x00000051, 0x00000004 },
{ 0x01e655b4, 0x00000002 },
{ 0x4401b0dc, 0x00000002 },
{ 0x01c110dc, 0x00000002 },
{ 0x2666705d, 0x00000018 },
{ 0x040c2565, 0x00000002 },
{ 0x0000005d, 0x00000018 },
{ 0x04002564, 0x00000002 },
{ 0x00007566, 0x00000002 },
{ 0x00000054, 0x00000004 },
{ 0x00401060, 0x00000008 },
{ 0x00101000, 0x00000002 },
{ 0x000d80ff, 0x00000002 },
{ 0x00800063, 0x00000008 },
{ 0x000f9000, 0x00000002 },
{ 0x000e00ff, 0x00000002 },
{ 0000000000, 0x00000006 },
{ 0x00000080, 0x00000018 },
{ 0x00000054, 0x00000004 },
{ 0x00007576, 0x00000002 },
{ 0x00065000, 0x00000002 },
{ 0x00009000, 0x00000002 },
{ 0x00041000, 0x00000002 },
{ 0x0c00350e, 0x00000002 },
{ 0x00049000, 0x00000002 },
{ 0x00051000, 0x00000002 },
{ 0x01e785f8, 0x00000002 },
{ 0x00200000, 0x00000002 },
{ 0x00600073, 0x0000000c },
{ 0x00007563, 0x00000002 },
{ 0x006075f0, 0x00000021 },
{ 0x20007068, 0x00000004 },
{ 0x00005068, 0x00000004 },
{ 0x00007576, 0x00000002 },
{ 0x00007577, 0x00000002 },
{ 0x0000750e, 0x00000002 },
{ 0x0000750f, 0x00000002 },
{ 0x00a05000, 0x00000002 },
{ 0x00600076, 0x0000000c },
{ 0x006075f0, 0x00000021 },
{ 0x000075f8, 0x00000002 },
{ 0x00000076, 0x00000004 },
{ 0x000a750e, 0x00000002 },
{ 0x0020750f, 0x00000002 },
{ 0x00600079, 0x00000004 },
{ 0x00007570, 0x00000002 },
{ 0x00007571, 0x00000002 },
{ 0x00007572, 0x00000006 },
{ 0x00005000, 0x00000002 },
{ 0x00a05000, 0x00000002 },
{ 0x00007568, 0x00000002 },
{ 0x00061000, 0x00000002 },
{ 0x00000084, 0x0000000c },
{ 0x00058000, 0x00000002 },
{ 0x0c607562, 0x00000002 },
{ 0x00000086, 0x00000004 },
{ 0x00600085, 0x00000004 },
{ 0x400070dd, 0000000000 },
{ 0x000380dd, 0x00000002 },
{ 0x00000093, 0x0000001c },
{ 0x00065095, 0x00000018 },
{ 0x040025bb, 0x00000002 },
{ 0x00061096, 0x00000018 },
{ 0x040075bc, 0000000000 },
{ 0x000075bb, 0x00000002 },
{ 0x000075bc, 0000000000 },
{ 0x00090000, 0x00000006 },
{ 0x00090000, 0x00000002 },
{ 0x000d8002, 0x00000006 },
{ 0x00005000, 0x00000002 },
{ 0x00007821, 0x00000002 },
{ 0x00007800, 0000000000 },
{ 0x00007821, 0x00000002 },
{ 0x00007800, 0000000000 },
{ 0x01665000, 0x00000002 },
{ 0x000a0000, 0x00000002 },
{ 0x000671cc, 0x00000002 },
{ 0x0286f1cd, 0x00000002 },
{ 0x000000a3, 0x00000010 },
{ 0x21007000, 0000000000 },
{ 0x000000aa, 0x0000001c },
{ 0x00065000, 0x00000002 },
{ 0x000a0000, 0x00000002 },
{ 0x00061000, 0x00000002 },
{ 0x000b0000, 0x00000002 },
{ 0x38067000, 0x00000002 },
{ 0x000a00a6, 0x00000004 },
{ 0x20007000, 0000000000 },
{ 0x01200000, 0x00000002 },
{ 0x20077000, 0x00000002 },
{ 0x01200000, 0x00000002 },
{ 0x20007000, 0000000000 },
{ 0x00061000, 0x00000002 },
{ 0x0120751b, 0x00000002 },
{ 0x8040750a, 0x00000002 },
{ 0x8040750b, 0x00000002 },
{ 0x00110000, 0x00000002 },
{ 0x000380dd, 0x00000002 },
{ 0x000000bd, 0x0000001c },
{ 0x00061096, 0x00000018 },
{ 0x844075bd, 0x00000002 },
{ 0x00061095, 0x00000018 },
{ 0x840075bb, 0x00000002 },
{ 0x00061096, 0x00000018 },
{ 0x844075bc, 0x00000002 },
{ 0x000000c0, 0x00000004 },
{ 0x804075bd, 0x00000002 },
{ 0x800075bb, 0x00000002 },
{ 0x804075bc, 0x00000002 },
{ 0x00108000, 0x00000002 },
{ 0x01400000, 0x00000002 },
{ 0x006000c4, 0x0000000c },
{ 0x20c07000, 0x00000020 },
{ 0x000000c6, 0x00000012 },
{ 0x00800000, 0x00000006 },
{ 0x0080751d, 0x00000006 },
{ 0x000025bb, 0x00000002 },
{ 0x000040c0, 0x00000004 },
{ 0x0000775c, 0x00000002 },
{ 0x00a05000, 0x00000002 },
{ 0x00661000, 0x00000002 },
{ 0x0460275d, 0x00000020 },
{ 0x00004000, 0000000000 },
{ 0x00007999, 0x00000002 },
{ 0x00a05000, 0x00000002 },
{ 0x00661000, 0x00000002 },
{ 0x0460299b, 0x00000020 },
{ 0x00004000, 0000000000 },
{ 0x01e00830, 0x00000002 },
{ 0x21007000, 0000000000 },
{ 0x00005000, 0x00000002 },
{ 0x00038042, 0x00000002 },
{ 0x040025e0, 0x00000002 },
{ 0x000075e1, 0000000000 },
{ 0x00000001, 0000000000 },
{ 0x000380d9, 0x00000002 },
{ 0x04007394, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
};
// r300 microcode
static const uint32 r300_cp_microcode[][2] = {
{ 0x4200e000, 0000000000 },
{ 0x4000e000, 0000000000 },
{ 0x000000af, 0x00000008 },
{ 0x000000b3, 0x00000008 },
{ 0x6c5a504f, 0000000000 },
{ 0x4f4f497a, 0000000000 },
{ 0x5a578288, 0000000000 },
{ 0x4f91906a, 0000000000 },
{ 0x4f4f4f4f, 0000000000 },
{ 0x4fe24f44, 0000000000 },
{ 0x4f9c9c9c, 0000000000 },
{ 0xdc4f4fde, 0000000000 },
{ 0xa1cd4f4f, 0000000000 },
{ 0xd29d9d9d, 0000000000 },
{ 0x4f0f9fd7, 0000000000 },
{ 0x000ca000, 0x00000004 },
{ 0x000d0012, 0x00000038 },
{ 0x0000e8b4, 0x00000004 },
{ 0x000d0014, 0x00000038 },
{ 0x0000e8b6, 0x00000004 },
{ 0x000d0016, 0x00000038 },
{ 0x0000e854, 0x00000004 },
{ 0x000d0018, 0x00000038 },
{ 0x0000e855, 0x00000004 },
{ 0x000d001a, 0x00000038 },
{ 0x0000e856, 0x00000004 },
{ 0x000d001c, 0x00000038 },
{ 0x0000e857, 0x00000004 },
{ 0x000d001e, 0x00000038 },
{ 0x0000e824, 0x00000004 },
{ 0x000d0020, 0x00000038 },
{ 0x0000e825, 0x00000004 },
{ 0x000d0022, 0x00000038 },
{ 0x0000e830, 0x00000004 },
{ 0x000d0024, 0x00000038 },
{ 0x0000f0c0, 0x00000004 },
{ 0x000d0026, 0x00000038 },
{ 0x0000f0c1, 0x00000004 },
{ 0x000d0028, 0x00000038 },
{ 0x0000f041, 0x00000004 },
{ 0x000d002a, 0x00000038 },
{ 0x0000f184, 0x00000004 },
{ 0x000d002c, 0x00000038 },
{ 0x0000f185, 0x00000004 },
{ 0x000d002e, 0x00000038 },
{ 0x0000f186, 0x00000004 },
{ 0x000d0030, 0x00000038 },
{ 0x0000f187, 0x00000004 },
{ 0x000d0032, 0x00000038 },
{ 0x0000f180, 0x00000004 },
{ 0x000d0034, 0x00000038 },
{ 0x0000f393, 0x00000004 },
{ 0x000d0036, 0x00000038 },
{ 0x0000f38a, 0x00000004 },
{ 0x000d0038, 0x00000038 },
{ 0x0000f38e, 0x00000004 },
{ 0x0000e821, 0x00000004 },
{ 0x0140a000, 0x00000004 },
{ 0x00000043, 0x00000018 },
{ 0x00cce800, 0x00000004 },
{ 0x001b0001, 0x00000004 },
{ 0x08004800, 0x00000004 },
{ 0x001b0001, 0x00000004 },
{ 0x08004800, 0x00000004 },
{ 0x001b0001, 0x00000004 },
{ 0x08004800, 0x00000004 },
{ 0x0000003a, 0x00000008 },
{ 0x0000a000, 0000000000 },
{ 0x02c0a000, 0x00000004 },
{ 0x000ca000, 0x00000004 },
{ 0x00130000, 0x00000004 },
{ 0x000c2000, 0x00000004 },
{ 0xc980c045, 0x00000008 },
{ 0x2000451d, 0x00000004 },
{ 0x0000e580, 0x00000004 },
{ 0x000ce581, 0x00000004 },
{ 0x08004580, 0x00000004 },
{ 0x000ce581, 0x00000004 },
{ 0x0000004c, 0x00000008 },
{ 0x0000a000, 0000000000 },
{ 0x000c2000, 0x00000004 },
{ 0x0000e50e, 0x00000004 },
{ 0x00032000, 0x00000004 },
{ 0x00022056, 0x00000028 },
{ 0x00000056, 0x00000024 },
{ 0x0800450f, 0x00000004 },
{ 0x0000a050, 0x00000008 },
{ 0x0000e565, 0x00000004 },
{ 0x0000e566, 0x00000004 },
{ 0x00000057, 0x00000008 },
{ 0x03cca5b4, 0x00000004 },
{ 0x05432000, 0x00000004 },
{ 0x00022000, 0x00000004 },
{ 0x4ccce063, 0x00000030 },
{ 0x08274565, 0x00000004 },
{ 0x00000063, 0x00000030 },
{ 0x08004564, 0x00000004 },
{ 0x0000e566, 0x00000004 },
{ 0x0000005a, 0x00000008 },
{ 0x00802066, 0x00000010 },
{ 0x00202000, 0x00000004 },
{ 0x001b00ff, 0x00000004 },
{ 0x01000069, 0x00000010 },
{ 0x001f2000, 0x00000004 },
{ 0x001c00ff, 0x00000004 },
{ 0000000000, 0x0000000c },
{ 0x00000085, 0x00000030 },
{ 0x0000005a, 0x00000008 },
{ 0x0000e576, 0x00000004 },
{ 0x000ca000, 0x00000004 },
{ 0x00012000, 0x00000004 },
{ 0x00082000, 0x00000004 },
{ 0x1800650e, 0x00000004 },
{ 0x00092000, 0x00000004 },
{ 0x000a2000, 0x00000004 },
{ 0x000f0000, 0x00000004 },
{ 0x00400000, 0x00000004 },
{ 0x00000079, 0x00000018 },
{ 0x0000e563, 0x00000004 },
{ 0x00c0e5f9, 0x000000c2 },
{ 0x0000006e, 0x00000008 },
{ 0x0000a06e, 0x00000008 },
{ 0x0000e576, 0x00000004 },
{ 0x0000e577, 0x00000004 },
{ 0x0000e50e, 0x00000004 },
{ 0x0000e50f, 0x00000004 },
{ 0x0140a000, 0x00000004 },
{ 0x0000007c, 0x00000018 },
{ 0x00c0e5f9, 0x000000c2 },
{ 0x0000007c, 0x00000008 },
{ 0x0014e50e, 0x00000004 },
{ 0x0040e50f, 0x00000004 },
{ 0x00c0007f, 0x00000008 },
{ 0x0000e570, 0x00000004 },
{ 0x0000e571, 0x00000004 },
{ 0x0000e572, 0x0000000c },
{ 0x0000a000, 0x00000004 },
{ 0x0140a000, 0x00000004 },
{ 0x0000e568, 0x00000004 },
{ 0x000c2000, 0x00000004 },
{ 0x00000089, 0x00000018 },
{ 0x000b0000, 0x00000004 },
{ 0x18c0e562, 0x00000004 },
{ 0x0000008b, 0x00000008 },
{ 0x00c0008a, 0x00000008 },
{ 0x000700e4, 0x00000004 },
{ 0x00000097, 0x00000038 },
{ 0x000ca099, 0x00000030 },
{ 0x080045bb, 0x00000004 },
{ 0x000c209a, 0x00000030 },
{ 0x0800e5bc, 0000000000 },
{ 0x0000e5bb, 0x00000004 },
{ 0x0000e5bc, 0000000000 },
{ 0x00120000, 0x0000000c },
{ 0x00120000, 0x00000004 },
{ 0x001b0002, 0x0000000c },
{ 0x0000a000, 0x00000004 },
{ 0x0000e821, 0x00000004 },
{ 0x0000e800, 0000000000 },
{ 0x0000e821, 0x00000004 },
{ 0x0000e82e, 0000000000 },
{ 0x02cca000, 0x00000004 },
{ 0x00140000, 0x00000004 },
{ 0x000ce1cc, 0x00000004 },
{ 0x050de1cd, 0x00000004 },
{ 0x000000a7, 0x00000020 },
{ 0x4200e000, 0000000000 },
{ 0x000000ae, 0x00000038 },
{ 0x000ca000, 0x00000004 },
{ 0x00140000, 0x00000004 },
{ 0x000c2000, 0x00000004 },
{ 0x00160000, 0x00000004 },
{ 0x700ce000, 0x00000004 },
{ 0x001400aa, 0x00000008 },
{ 0x4000e000, 0000000000 },
{ 0x02400000, 0x00000004 },
{ 0x400ee000, 0x00000004 },
{ 0x02400000, 0x00000004 },
{ 0x4000e000, 0000000000 },
{ 0x000c2000, 0x00000004 },
{ 0x0240e51b, 0x00000004 },
{ 0x0080e50a, 0x00000005 },
{ 0x0080e50b, 0x00000005 },
{ 0x00220000, 0x00000004 },
{ 0x000700e4, 0x00000004 },
{ 0x000000c1, 0x00000038 },
{ 0x000c209a, 0x00000030 },
{ 0x0880e5bd, 0x00000005 },
{ 0x000c2099, 0x00000030 },
{ 0x0800e5bb, 0x00000005 },
{ 0x000c209a, 0x00000030 },
{ 0x0880e5bc, 0x00000005 },
{ 0x000000c4, 0x00000008 },
{ 0x0080e5bd, 0x00000005 },
{ 0x0000e5bb, 0x00000005 },
{ 0x0080e5bc, 0x00000005 },
{ 0x00210000, 0x00000004 },
{ 0x02800000, 0x00000004 },
{ 0x00c000c8, 0x00000018 },
{ 0x4180e000, 0x00000040 },
{ 0x000000ca, 0x00000024 },
{ 0x01000000, 0x0000000c },
{ 0x0100e51d, 0x0000000c },
{ 0x000045bb, 0x00000004 },
{ 0x000080c4, 0x00000008 },
{ 0x0000f3ce, 0x00000004 },
{ 0x0140a000, 0x00000004 },
{ 0x00cc2000, 0x00000004 },
{ 0x08c053cf, 0x00000040 },
{ 0x00008000, 0000000000 },
{ 0x0000f3d2, 0x00000004 },
{ 0x0140a000, 0x00000004 },
{ 0x00cc2000, 0x00000004 },
{ 0x08c053d3, 0x00000040 },
{ 0x00008000, 0000000000 },
{ 0x0000f39d, 0x00000004 },
{ 0x0140a000, 0x00000004 },
{ 0x00cc2000, 0x00000004 },
{ 0x08c0539e, 0x00000040 },
{ 0x00008000, 0000000000 },
{ 0x03c00830, 0x00000004 },
{ 0x4200e000, 0000000000 },
{ 0x0000a000, 0x00000004 },
{ 0x200045e0, 0x00000004 },
{ 0x0000e5e1, 0000000000 },
{ 0x00000001, 0000000000 },
{ 0x000700e1, 0x00000004 },
{ 0x0800e394, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
};
#endif

View File

@ -0,0 +1,655 @@
/*
Copyright (c) 2002, Thomas Kurschel
Part of Radeon accelerant
CP initialization/sync/cleanup.
It also handles command buffer synchronization.
non-local memory is used as following:
- 2048 dwords for ring buffer
- 253 indirect buffers a 4k (1024 dwords)
- 8 dwords for returned data (i.e. current read ptr)
& 6 dwords for "scratch registers"
usage of scratch registers:
- reg 0 = reached engine.count
with a granularity of 4 KByte, we need 2+253+1=256 blocks, which is exactly 1 MB
*/
#include "radeon_driver.h"
#include "CPMicroCode.h"
#include "mmio.h"
#include "cp_regs.h"
#include "pll_regs.h"
#include "rbbm_regs.h"
#include "buscntrl_regs.h"
#include "utils.h"
#include "pll_access.h"
#include "log_coll.h"
#include "log_enum.h"
#include <string.h>
#if 0
// macros for user-space
#define ALLOC_MEM( asize, mem_type, aglobal, handle, offset ) \
{ \
radeon_alloc_mem am; \
\
am.magic = RADEON_PRIVATE_DATA_MAGIC; \
am.size = (asize) * 4; \
am.memory_type = (mt_nonlocal); \
am.global = (aglobal); \
\
res = ioctl( ai->fd, RADEON_ALLOC_MEM, &am ); \
if( res == B_OK ) \
*(handle) = am.handle; \
*(offset) = am.offset; \
}
#define MEM2CPU( mem ) \
((uint32 *)(ai->mapped_memory[(mem).memory_type].data + (mem).offset))
#define MEM2GC( mem ) ((mem).offset + si->memory[(mem).memory_type].virtual_addr_start)
#define FREE_MEM( mem_type, handle ) \
{ \
radeon_free_mem fm; \
\
fm.magic = RADEON_PRIVATE_DATA_MAGIC; \
fm.memory_type = mem_type; \
fm.handle = offset; \
\
ioctl( ai->fd, RADEON_FREE_MEM, &fm ); \
}
#else
// macros for kernel-space
// allocate memory
// if memory_type is non-local, it is replaced with default non-local type
#define ALLOC_MEM( asize, mem_type, aglobal, handle, offset ) \
if( mem_type == mt_nonlocal ) \
mem_type = di->si->nonlocal_type; \
res = mem_alloc( di->memmgr[mem_type], asize, NULL, handle, offset );
// get address as seen by program to access allocated memory
// (memory_type must _not_ be non-local, see ALLOC_MEM)
#define MEM2CPU( memory_type, offset ) \
((uint8 *)(memory_type == mt_local ? di->si->local_mem : \
(memory_type == mt_PCI ? di->pci_gart.buffer.ptr : di->agp_gart.buffer.ptr)) \
+ (offset))
// get graphics card's virtual address of allocated memory
// (memory_type must _not_ be non-local, see ALLOC_MEM)
#define MEM2GC( memory_type, offset ) \
(di->si->memory[(memory_type)].virtual_addr_start + (offset))
// free memory
// if memory_type is non-local, it is replaced with default non-local type
#define FREE_MEM( mem_type, handle ) \
mem_free( \
di->memmgr[ mem_type == mt_nonlocal ? di->si->nonlocal_type : mem_type], \
handle, NULL );
#endif
void Radeon_DiscardAllIndirectBuffers( device_info *di );
#define RADEON_SCRATCH_REG_OFFSET 32
void Radeon_FlushPixelCache( device_info *di );
// wait until engine is idle;
// acquire_lock - true, if lock must be hold
// false, if lock is already acquired
// keep_lock - true, keep lock on exit (only valid if acquire_lock is true)
void Radeon_WaitForIdle( device_info *di, bool acquire_lock, bool keep_lock )
{
if( acquire_lock )
ACQUIRE_BEN( di->si->cp.lock );
Radeon_WaitForFifo( di, 64 );
while( 1 ) {
bigtime_t start_time = system_time();
do {
if( (INREG( di->regs, RADEON_RBBM_STATUS ) & RADEON_RBBM_ACTIVE) == 0 ) {
Radeon_FlushPixelCache( di );
if( acquire_lock && !keep_lock)
RELEASE_BEN( di->si->cp.lock );
return;
}
snooze( 1 );
} while( system_time() - start_time < 1000000 );
SHOW_ERROR( 3, "Engine didn't become idle (rbbm_status=%lx, cp_stat=%lx, tlb_address=%lx, tlb_data=%lx)",
INREG( di->regs, RADEON_RBBM_STATUS ),
INREG( di->regs, RADEON_CP_STAT ),
INREG( di->regs, RADEON_AIC_TLB_ADDR ),
INREG( di->regs, RADEON_AIC_TLB_DATA ));
LOG( di->si->log, _Radeon_WaitForIdle );
Radeon_ResetEngine( di );
}
}
// wait until "entries" FIFO entries are empty
// lock must be hold
void Radeon_WaitForFifo( device_info *di, int entries )
{
while( 1 ) {
bigtime_t start_time = system_time();
do {
int slots = INREG( di->regs, RADEON_RBBM_STATUS ) & RADEON_RBBM_FIFOCNT_MASK;
if ( slots >= entries )
return;
snooze( 1 );
} while( system_time() - start_time < 1000000 );
LOG( di->si->log, _Radeon_WaitForFifo );
Radeon_ResetEngine( di );
}
}
// flush pixel cache of graphics card
void Radeon_FlushPixelCache( device_info *di )
{
bigtime_t start_time;
OUTREGP( di->regs, RADEON_RB2D_DSTCACHE_CTLSTAT, RADEON_RB2D_DC_FLUSH_ALL,
~RADEON_RB2D_DC_FLUSH_ALL );
start_time = system_time();
do {
if( (INREG( di->regs, RADEON_RB2D_DSTCACHE_CTLSTAT )
& RADEON_RB2D_DC_BUSY) == 0 )
return;
snooze( 1 );
} while( system_time() - start_time < 1000000 );
LOG( di->si->log, _Radeon_FlushPixelCache );
SHOW_ERROR0( 0, "pixel cache didn't become empty" );
}
// reset graphics card's engine
// lock must be hold
void Radeon_ResetEngine( device_info *di )
{
vuint8 *regs = di->regs;
shared_info *si = di->si;
uint32 clock_cntl_index, mclk_cntl, rbbm_soft_reset, host_path_cntl;
uint32 cur_read_ptr;
SHOW_FLOW0( 3, "" );
Radeon_FlushPixelCache( di );
clock_cntl_index = INREG( regs, RADEON_CLOCK_CNTL_INDEX );
R300_PLLFix( di->regs, di->asic );
// OUCH!
// XFree disables any kind of automatic power power management
// because of bugs of some ASIC revision (seems like the revisions
// cannot be read out)
// -> this is a very bad idea, especially when it comes to laptops
// I comment it out for now, let's hope noone takes notice
if( di->num_heads > 1 ) {
Radeon_OUTPLLP( regs, di->asic, RADEON_SCLK_CNTL,
RADEON_CP_MAX_DYN_STOP_LAT |
RADEON_SCLK_FORCEON_MASK,
~RADEON_DYN_STOP_LAT_MASK );
/* if( ai->si->asic == rt_rv200 ) {
Radeon_OUTPLLP( ai, RADEON_SCLK_MORE_CNTL,
RADEON_SCLK_MORE_FORCEON, ~0 );
}*/
}
mclk_cntl = Radeon_INPLL( regs, di->asic, RADEON_MCLK_CNTL );
// enable clock of units to be reset
Radeon_OUTPLL( regs, di->asic, RADEON_MCLK_CNTL, mclk_cntl |
RADEON_FORCEON_MCLKA |
RADEON_FORCEON_MCLKB |
RADEON_FORCEON_YCLKA |
RADEON_FORCEON_YCLKB |
RADEON_FORCEON_MC |
RADEON_FORCEON_AIC );
// do the reset
host_path_cntl = INREG( regs, RADEON_HOST_PATH_CNTL );
rbbm_soft_reset = INREG( regs, RADEON_RBBM_SOFT_RESET );
switch( di->asic ) {
case rt_r300:
OUTREG( regs, RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset |
RADEON_SOFT_RESET_CP |
RADEON_SOFT_RESET_HI |
RADEON_SOFT_RESET_E2 |
RADEON_SOFT_RESET_AIC ));
INREG( regs, RADEON_RBBM_SOFT_RESET);
OUTREG( regs, RADEON_RBBM_SOFT_RESET, 0);
// this bit has no description
OUTREGP( regs, RADEON_RB2D_DSTCACHE_MODE, (1 << 17), ~0 );
break;
default:
OUTREG( regs, RADEON_RBBM_SOFT_RESET, rbbm_soft_reset |
RADEON_SOFT_RESET_CP |
RADEON_SOFT_RESET_HI |
RADEON_SOFT_RESET_SE |
RADEON_SOFT_RESET_RE |
RADEON_SOFT_RESET_PP |
RADEON_SOFT_RESET_E2 |
RADEON_SOFT_RESET_RB |
RADEON_SOFT_RESET_AIC );
INREG( regs, RADEON_RBBM_SOFT_RESET );
OUTREG( regs, RADEON_RBBM_SOFT_RESET, rbbm_soft_reset &
~( RADEON_SOFT_RESET_CP |
RADEON_SOFT_RESET_HI |
RADEON_SOFT_RESET_SE |
RADEON_SOFT_RESET_RE |
RADEON_SOFT_RESET_PP |
RADEON_SOFT_RESET_E2 |
RADEON_SOFT_RESET_RB |
RADEON_SOFT_RESET_AIC ) );
INREG( regs, RADEON_RBBM_SOFT_RESET );
}
OUTREG( regs, RADEON_HOST_PATH_CNTL, host_path_cntl | RADEON_HDP_SOFT_RESET );
INREG( regs, RADEON_HOST_PATH_CNTL );
OUTREG( regs, RADEON_HOST_PATH_CNTL, host_path_cntl );
// restore regs
OUTREG( regs, RADEON_RBBM_SOFT_RESET, rbbm_soft_reset);
OUTREG( regs, RADEON_CLOCK_CNTL_INDEX, clock_cntl_index );
R300_PLLFix( regs, di->asic );
Radeon_OUTPLL( regs, di->asic, RADEON_MCLK_CNTL, mclk_cntl );
// reset ring buffer
cur_read_ptr = INREG( regs, RADEON_CP_RB_RPTR );
OUTREG( regs, RADEON_CP_RB_WPTR, cur_read_ptr );
//if( si->cp.ring.head ) {
// during init, there are no feedback data
if( si->cp.feedback.mem_handle != 0 ) {
*(uint32 *)MEM2CPU( si->cp.feedback.mem_type, si->cp.feedback.head_mem_offset) =
cur_read_ptr;
// *si->cp.ring.head = cur_read_ptr;
si->cp.ring.tail = cur_read_ptr;
}
++si->engine.count;
// mark all buffers as being finished
Radeon_DiscardAllIndirectBuffers( di );
return;
}
// upload Micro-Code of CP
static void loadMicroEngineRAMData( device_info *di )
{
int i;
const uint32 (*microcode)[2];
SHOW_FLOW0( 3, "" );
switch( di->asic ) {
case rt_r300:
case rt_r300_4p:
case rt_rv350:
case rt_rv360:
case rt_r350:
case rt_r360:
microcode = r300_cp_microcode;
break;
case rt_r200:
//case rt_rv250:
//case rt_m9:
microcode = r200_cp_microcode;
break;
case rt_rs100:
default:
microcode = radeon_cp_microcode;
}
Radeon_WaitForIdle( di, false, false );
OUTREG( di->regs, RADEON_CP_ME_RAM_ADDR, 0 );
for ( i = 0 ; i < 256 ; i++ ) {
OUTREG( di->regs, RADEON_CP_ME_RAM_DATAH, microcode[i][1] );
OUTREG( di->regs, RADEON_CP_ME_RAM_DATAL, microcode[i][0] );
}
}
// aring_size - size of ring in dwords
static status_t initRingBuffer( device_info *di, int aring_size )
{
status_t res;
shared_info *si = di->si;
CP_info *cp = &si->cp;
vuint8 *regs = di->regs;
int32 offset;
memory_type_e memory_type;
memset( &cp->ring, 0, sizeof( cp->ring ));
// ring and indirect buffers can be either in AGP or PCI GART
// (it seems that they cannot be in graphics memory, at least
// I had serious coherency problems when I tried that)
memory_type = mt_nonlocal;
ALLOC_MEM( aring_size * 4, memory_type, true,
&cp->ring.mem_handle, &offset );
if( res != B_OK ) {
SHOW_ERROR0( 0, "Cannot allocate ring buffer" );
return res;
}
// setup CP buffer
cp->ring.mem_type = memory_type;
cp->ring.mem_offset = offset;
cp->ring.vm_base = MEM2GC( memory_type, offset );
cp->ring.size = aring_size;
cp->ring.tail_mask = aring_size - 1;
OUTREG( regs, RADEON_CP_RB_BASE, cp->ring.vm_base );
SHOW_INFO( 3, "CP buffer address=%lx", cp->ring.vm_base );
// set ring buffer size
// (it's log2 of qwords)
OUTREG( regs, RADEON_CP_RB_CNTL, log2( cp->ring.size / 2 ));
SHOW_INFO( 3, "CP buffer size mask=%d", log2( cp->ring.size / 2 ) );
// set write pointer delay to zero;
// we assume that memory synchronization is done correctly my MoBo
// and Radeon_SendCP contains a hack that hopefully fixes such problems
OUTREG( regs, RADEON_CP_RB_WPTR_DELAY, 0 );
memset( MEM2CPU( cp->ring.mem_type, cp->ring.mem_offset), 0, cp->ring.size * 4 );
// set CP buffer pointers
OUTREG( regs, RADEON_CP_RB_RPTR, 0 );
OUTREG( regs, RADEON_CP_RB_WPTR, 0 );
//*cp->ring.head = 0;
cp->ring.tail = 0;
}
static void uninitRingBuffer( device_info *di )
{
vuint8 *regs = di->regs;
// abort any activity
Radeon_ResetEngine( di );
// disable CP BM
OUTREG( regs, RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIDIS_INDDIS );
// read-back for flushing
INREG( regs, RADEON_CP_CSQ_CNTL );
FREE_MEM( mt_nonlocal, di->si->cp.ring.mem_handle );
}
static status_t initCPFeedback( device_info *di )
{
CP_info *cp = &di->si->cp;
vuint8 *regs = di->regs;
int32 offset;
memory_type_e memory_type;
status_t res;
// status information should be in PCI memory, so CPU can
// poll it without locking the bus (PCI memory is the only
// cachable memory available)
memory_type = mt_PCI;
ALLOC_MEM( RADEON_SCRATCH_REG_OFFSET + 0x40, memory_type, true,
&cp->feedback.mem_handle, &offset );
if( res != B_OK ) {
SHOW_ERROR0( 0, "Cannot allocate buffers for status information" );
return res;
}
// setup CP read pointer buffer
cp->feedback.mem_type = memory_type;
cp->feedback.head_mem_offset = offset;
cp->feedback.head_vm_address = MEM2GC( memory_type, cp->feedback.head_mem_offset );
OUTREG( regs, RADEON_CP_RB_RPTR_ADDR, cp->feedback.head_vm_address );
SHOW_INFO( 3, "CP read pointer buffer==%lx", cp->feedback.head_vm_address );
// setup scratch register buffer
cp->feedback.scratch_mem_offset = offset + RADEON_SCRATCH_REG_OFFSET;
cp->feedback.scratch_vm_start = MEM2GC( memory_type, cp->feedback.scratch_mem_offset );
OUTREG( regs, RADEON_SCRATCH_ADDR, cp->feedback.scratch_vm_start );
OUTREG( regs, RADEON_SCRATCH_UMSK, 0x3f );
*(uint32 *)MEM2CPU( cp->feedback.mem_type, cp->feedback.head_mem_offset) = 0;
memset( MEM2CPU( cp->feedback.mem_type, cp->feedback.scratch_mem_offset), 0, 0x40 );
//*cp->ring.head = 0;
}
static void uninitCPFeedback( device_info *di )
{
vuint8 *regs = di->regs;
// don't allow any scratch buffer update
OUTREG( regs, RADEON_SCRATCH_UMSK, 0x0 );
FREE_MEM( mt_PCI, di->si->cp.feedback.mem_handle );
}
static status_t initIndirectBuffers( device_info *di )
{
CP_info *cp = &di->si->cp;
int32 offset;
memory_type_e memory_type;
int i;
status_t res;
memory_type = mt_nonlocal;
ALLOC_MEM( NUM_INDIRECT_BUFFERS * INDIRECT_BUFFER_SIZE * 4, memory_type,
true, &cp->buffers.mem_handle, &offset );
if( res != B_OK ) {
SHOW_ERROR0( 0, "Cannot allocate indirect buffers" );
return B_ERROR;
}
cp->buffers.mem_type = memory_type;
cp->buffers.mem_offset = offset;
cp->buffers.vm_start = MEM2GC( memory_type, cp->buffers.mem_offset );
for( i = 0; i < NUM_INDIRECT_BUFFERS - 1; ++i ) {
cp->buffers.buffers[i].next = i + 1;
}
cp->buffers.buffers[i].next = -1;
cp->buffers.free_list = 0;
cp->buffers.oldest = -1;
cp->buffers.newest = -1;
cp->buffers.active_state = -1;
cp->buffers.cur_tag = 0;
memset( MEM2CPU( cp->buffers.mem_type, cp->buffers.mem_offset), 0,
NUM_INDIRECT_BUFFERS * INDIRECT_BUFFER_SIZE * 4 );
return B_OK;
}
static void uninitIndirectBuffers( device_info *di )
{
FREE_MEM( mt_nonlocal, di->si->cp.buffers.mem_handle );
}
// initialize CP so it's ready for BM
status_t Radeon_InitCP( device_info *di )
{
thread_id thid;
thread_info thinfo;
status_t res;
SHOW_FLOW0( 3, "" );
// this is _really_ necessary so functions like ResetEngine() know
// that the CP is not set up yet
memset( &di->si->cp, 0, sizeof( di->si->cp ));
if( (res = INIT_BEN( di->si->cp.lock, "Radeon CP" )) < 0 )
return res;
// HACK: change owner of benaphore semaphore to team of calling thread;
// reason: user code cannot acquire kernel semaphores, but the accelerant
// is in user space; interestingly, it's enough to change the semaphore's
// owner to _any_ non-system team (that's the only security check done by
// the kernel)
thid = find_thread( NULL );
get_thread_info( thid, &thinfo );
set_sem_owner( di->si->cp.lock.sem, thinfo.team );
// init raw CP
loadMicroEngineRAMData( di );
// do soft-reset
Radeon_ResetEngine( di );
// after warm-reset, the CP may still be active and thus react to
// register writes during initialization unpredictably, so we better
// stop it first
OUTREG( di->regs, RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIDIS_INDDIS );
INREG( di->regs, RADEON_CP_CSQ_CNTL );
// reset CP to make disabling active
Radeon_ResetEngine( di );
res = initRingBuffer( di, CP_RING_SIZE );
if( res < 0 )
goto err4;
res = initCPFeedback( di );
if( res < 0 )
goto err3;
res = initIndirectBuffers( di );
if( res < 0 )
goto err2;
// tell CP to use BM
Radeon_WaitForIdle( di, false, false );
// enable direct and indirect CP bus mastering
OUTREG( di->regs, RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIBM_INDBM );
// allow bus mastering in general
OUTREGP( di->regs, RADEON_BUS_CNTL, 0, ~RADEON_BUS_MASTER_DIS );
// don't allow mixing of 2D/3D/scratch/wait_until commands
// (in fact, this doesn't seem to make any difference as we do a
// manual sync in all these cases anyway)
OUTREG( di->regs, RADEON_ISYNC_CNTL,
RADEON_ISYNC_ANY2D_IDLE3D |
RADEON_ISYNC_ANY3D_IDLE2D |
RADEON_ISYNC_WAIT_IDLEGUI |
RADEON_ISYNC_CPSCRATCH_IDLEGUI );
SHOW_FLOW( 3, "bus_cntl=%lx", INREG( di->regs, RADEON_BUS_CNTL ));
SHOW_FLOW0( 3, "Done" );
return B_OK;
//err:
// uninitIndirectBuffers( ai );
err2:
uninitCPFeedback( di );
err3:
uninitRingBuffer( di );
err4:
DELETE_BEN( di->si->cp.lock );
return res;
}
// shutdown CP, freeing any memory
void Radeon_UninitCP( device_info *di )
{
vuint8 *regs = di->regs;
// abort any pending commands
Radeon_ResetEngine( di );
// disable CP BM
OUTREG( regs, RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIDIS_INDDIS );
// read-back for flushing
INREG( regs, RADEON_CP_CSQ_CNTL );
uninitRingBuffer( di );
uninitCPFeedback( di );
uninitIndirectBuffers( di );
DELETE_BEN( di->si->cp.lock );
}
// mark all indirect buffers as being free;
// this should only be called after a reset;
// lock must be hold
void Radeon_DiscardAllIndirectBuffers( device_info *di )
{
CP_info *cp = &di->si->cp;
// during init, there is no indirect buffer
if( cp->buffers.mem_handle == 0 )
return;
// mark all sent indirect buffers as free
while( cp->buffers.oldest != -1 ) {
indirect_buffer *oldest_buffer =
&cp->buffers.buffers[cp->buffers.oldest];
int tmp_oldest_buffer;
SHOW_FLOW( 0, "%d", cp->buffers.oldest );
// remove buffer from "used" list
tmp_oldest_buffer = oldest_buffer->next;
if( tmp_oldest_buffer == -1 )
cp->buffers.newest = -1;
// put it on free list
oldest_buffer->next = cp->buffers.free_list;
cp->buffers.free_list = cp->buffers.oldest;
cp->buffers.oldest = tmp_oldest_buffer;
}
}

View File

@ -0,0 +1,177 @@
/*
Copyright (c) 2002-04, Thomas Kurschel
Part of Radeon accelerant
DMA engine handling.
Currently, VID DMA is always used and data is always copied from
graphics memory to other memory.
*/
#include "radeon_driver.h"
#include "mmio.h"
#include "rbbm_regs.h"
#include "dma_regs.h"
#include <string.h>
// this is arbitrary and hopefully sufficiently high
#define RADEON_MAX_DMA_SIZE 16*1024*1024
// initialize DMA engine
status_t Radeon_InitDMA( device_info *di )
{
status_t res;
// allocate descriptor table in graphics mem
// (docu says that is _must_ be in graphics mem)
di->dma_desc_max_num = RADEON_MAX_DMA_SIZE / 4096;
res = mem_alloc( di->memmgr[mt_local], di->dma_desc_max_num * sizeof( DMA_descriptor ), 0,
&di->dma_desc_handle, &di->dma_desc_offset );
if( res != B_OK )
return res;
// allow DMA IRQ
OUTREGP( di->regs, RADEON_GEN_INT_CNTL, RADEON_VIDDMA_MASK, ~RADEON_VIDDMA_MASK );
// acknowledge possibly pending IRQ
OUTREG( di->regs, RADEON_GEN_INT_STATUS, RADEON_VIDDMA_AK );
return B_OK;
}
// prepare DMA engine to copy data from graphics mem to other mem
static status_t Radeon_PrepareDMA(
device_info *di, uint32 src, char *target, size_t size, bool lock_mem, bool contiguous )
{
physical_entry map[16];
status_t res;
DMA_descriptor *cur_desc;
int num_desc;
if( lock_mem && !contiguous ) {
res = lock_memory( target, size, B_DMA_IO | B_READ_DEVICE );
if( res != B_OK ) {
SHOW_ERROR( 2, "Cannot lock memory (%s)", strerror( res ));
return res;
}
}
// adjust virtual address for graphics card
src += di->si->memory[mt_local].virtual_addr_start;
cur_desc = (DMA_descriptor *)(di->si->local_mem + di->dma_desc_offset);
num_desc = 0;
// memory may be fragmented, so we create S/G list
while( size > 0 ) {
int i;
if( contiguous ) {
// if memory is contiguous, ask for start address only to reduce work
get_memory_map( target, 1, map, 16 );
// replace received size with total size
map[0].size = size;
} else {
get_memory_map( target, size, map, 16 );
}
for( i = 0; i < 16; ++i ) {
uint32 address = (uint32)map[i].address;
size_t contig_size = map[i].size;
if( contig_size == 0 )
break;
target += contig_size;
while( contig_size > 0 ) {
size_t cur_size;
cur_size = min( contig_size, RADEON_DMA_DESC_MAX_SIZE );
if( ++num_desc > di->dma_desc_max_num ) {
SHOW_ERROR( 2, "Overflow of DMA descriptors, %ld bytes left", size );
res = B_BAD_VALUE;
goto err;
}
cur_desc->src_address = src;
cur_desc->dest_address = address;
cur_desc->command = cur_size;
cur_desc->res = 0;
++cur_desc;
address += cur_size;
contig_size -= cur_size;
src += cur_size;
size -= cur_size;
}
}
}
// mark last descriptor as being last one
(cur_desc - 1)->command |= RADEON_DMA_COMMAND_EOL;
return B_OK;
err:
if( lock_mem && !contiguous )
unlock_memory( target, size, B_DMA_IO| B_READ_DEVICE );
return res;
}
// finish DMA
// caller must ensure that DMA channel has stopped
static void Radeon_FinishDMA(
device_info *di, uint32 src, char *target, size_t size, bool lock_mem, bool contiguous )
{
if( lock_mem && !contiguous )
unlock_memory( target, size, B_DMA_IO| B_READ_DEVICE );
}
// copy from graphics memory to other memory via DMA
// src - offset in graphics mem
// target - target address
// size - number of bytes to copy
// lock_mem - true, if memory is not locked
// contiguous - true, if memory is physically contiguous (implies lock_mem=false)
status_t Radeon_DMACopy(
device_info *di, uint32 src, char *target, size_t size, bool lock_mem, bool contiguous )
{
status_t res;
/*SHOW_FLOW( 0, "src=%ld, target=%p, size=%ld, lock_mem=%d, contiguous=%d",
src, target, size, lock_mem, contiguous );*/
res = Radeon_PrepareDMA( di, src, target, size, lock_mem, contiguous );
if( res != B_OK )
return res;
//SHOW_FLOW0( 0, "2" );
OUTREG( di->regs, RADEON_DMA_VID_TABLE_ADDR, di->si->memory[mt_local].virtual_addr_start +
di->dma_desc_offset );
res = acquire_sem_etc( di->dma_sem, 1, B_RELATIVE_TIMEOUT, 1000000 );
// be sure that transmission is really finished
while( (INREG( di->regs, RADEON_DMA_VID_STATUS ) & RADEON_DMA_STATUS_ACTIVE) != 0 ) {
SHOW_FLOW0( 0, "DMA transmission still active" );
snooze( 1000 );
}
Radeon_FinishDMA( di, src, target, size, lock_mem, contiguous );
//SHOW_FLOW0( 0, "3" );
return res;
}

View File

@ -2,17 +2,27 @@ SubDir OBOS_TOP src add-ons kernel drivers graphics radeon ;
UsePrivateHeaders graphics ;
UsePrivateHeaders [ FDirName graphics radeon ] ;
UsePrivateHeaders [ FDirName graphics common ] ;
StaticLibrary radeon :
pll_access.c
utils.c
;
R5KernelAddon radeon.driver : kernel drivers bin :
driver.c
agp.c
bios.c
detect.c
dma.c
DMA.c
global_data.c
init.c
irq.c
memmgr.c
mem_controller.c
CP_setup.c
PCI_GART.c
vip.c
: libgraphicscommon.a libradeon.a
;
#Package openbeos-radeon-cvs :

View File

@ -0,0 +1,279 @@
/*
Copyright (c) 2002, Thomas Kurschel
Part of Radeon kernel driver
PCI GART.
Currently, we use PCI DMA. Changing to AGP would
only affect this file, but AGP-GART is specific to
the chipset of the motherboard, and as DMA is really
overkill for 2D, I cannot bother writing a dozen
of AGP drivers just to gain little extra speedup.
*/
#include "radeon_driver.h"
#include <malloc.h>
#include <image.h>
#include "mmio.h"
#include "buscntrl_regs.h"
#include "memcntrl_regs.h"
#include "cp_regs.h"
#include <string.h>
#if 1
// create actual GART buffer
static status_t createGARTBuffer( GART_info *gart, size_t size )
{
SHOW_FLOW0( 3, "" );
gart->buffer.size = size = (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
// if this buffer is used for PCI BM, cache snooping
// takes care of syncing memory accesses; if used for AGP,
// we'll have to access via AGP aperture (and mark aperture
// as write-combined) as cache consistency doesn't need to
// be guaranteed
// the specs say that some chipsets do kind of lazy flushing
// so the graphics card may read obsolete data; up to now
// we use PCI only where this shouldn't happen by design;
// if we change to AGP we may tweak the pre-charge time of
// the write buffer pointer
// as some variables in accelerant point directly into
// the DMA buffer, we have to grant access for all apps
gart->buffer.area = create_area( "Radeon PCI GART buffer",
&gart->buffer.ptr, B_ANY_KERNEL_ADDRESS,
size, B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA );
if( gart->buffer.area < 0 ) {
SHOW_ERROR( 1, "cannot create PCI GART buffer (%s)",
strerror( gart->buffer.area ));
return gart->buffer.area;
}
gart->buffer.unaligned_area = -1;
memset( gart->buffer.ptr, 0, size );
return B_OK;
}
#else
static status_t createGARTBuffer( GART_info *gart, size_t size )
{
physical_entry map[1];
void *unaligned_addr, *aligned_phys;
SHOW_FLOW0( 3, "" );
gart->buffer.size = size = (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
// we allocate an contiguous area having twice the size
// to be able to find an aligned, contiguous range within it;
// the graphics card doesn't care, but the CPU cannot
// make an arbitrary area WC'ed, at least elder ones
// question: is this necessary for a PCI GART because of bus snooping?
gart->buffer.unaligned_area = create_area( "Radeon PCI GART buffer",
&unaligned_addr, B_ANY_KERNEL_ADDRESS,
2 * size, B_CONTIGUOUS/*B_FULL_LOCK*/, B_READ_AREA | B_WRITE_AREA );
if( gart->buffer.unaligned_area < 0 ) {
SHOW_ERROR( 1, "cannot create PCI GART buffer (%s)",
strerror( gart->buffer.unaligned_area ));
return gart->buffer.unaligned_area;
}
get_memory_map( unaligned_addr, B_PAGE_SIZE, map, 1 );
aligned_phys =
(void **)(((uint32)map[0].address + size - 1) & ~(size - 1));
SHOW_FLOW( 3, "aligned_phys=%p", aligned_phys );
gart->buffer.area = map_physical_memory( "Radeon aligned PCI GART buffer",
aligned_phys,
size, B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
B_READ_AREA | B_WRITE_AREA, &gart->buffer.ptr );
if( gart->buffer.area < 0 ) {
SHOW_ERROR0( 3, "cannot map buffer with WC" );
gart->buffer.area = map_physical_memory( "Radeon aligned PCI GART buffer",
aligned_phys,
size, B_ANY_KERNEL_BLOCK_ADDRESS,
B_READ_AREA | B_WRITE_AREA, &gart->buffer.ptr );
}
if( gart->buffer.area < 0 ) {
SHOW_ERROR0( 1, "cannot map GART buffer" );
delete_area( gart->buffer.unaligned_area );
gart->buffer.unaligned_area = -1;
return gart->buffer.area;
}
memset( gart->buffer.ptr, 0, size );
return B_OK;
}
#endif
// init GATT (could be used for both PCI and AGP)
static status_t initGATT( GART_info *gart )
{
physical_entry *map;
physical_entry PTB_map[1];
size_t map_count;
int i;
uint32 *gatt_entry;
size_t num_pages;
SHOW_FLOW0( 3, "" );
num_pages = (gart->buffer.size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
// GART must be contignuous
gart->GATT.area = create_area( "Radeon GATT", (void **)&gart->GATT.ptr,
B_ANY_KERNEL_ADDRESS,
(num_pages * sizeof( uint32 ) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1),
B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA );
if( gart->GATT.area < 0 ) {
SHOW_ERROR( 1, "cannot create GATT table (%s)",
strerror( gart->GATT.area ));
return gart->GATT.area;
}
get_memory_map( gart->GATT.ptr, B_PAGE_SIZE, PTB_map, 1 );
gart->GATT.phys = (uint32)PTB_map[0].address;
SHOW_INFO( 3, "GATT_ptr=%p, GATT_phys=%p", gart->GATT.ptr,
(void *)gart->GATT.phys );
// get address mapping
memset( gart->GATT.ptr, 0, num_pages * sizeof( uint32 ));
map_count = num_pages + 1;
map = malloc( map_count * sizeof( physical_entry ) );
get_memory_map( gart->buffer.ptr, gart->buffer.size, map, map_count );
// the following looks a bit strange as the kernel
// combines successive entries
gatt_entry = gart->GATT.ptr;
for( i = 0; i < map_count; ++i ) {
uint32 addr = (uint32)map[i].address;
size_t size = map[i].size;
if( size == 0 )
break;
while( size > 0 ) {
*gatt_entry++ = addr;
//SHOW_FLOW( 3, "%lx", *(gart_entry-1) );
addr += ATI_PCIGART_PAGE_SIZE;
size -= ATI_PCIGART_PAGE_SIZE;
}
}
free( map );
if( i == map_count ) {
// this case should never happen
SHOW_ERROR0( 0, "memory map of GART buffer too large!" );
delete_area( gart->GATT.area );
gart->GATT.area = -1;
return B_ERROR;
}
// this might be a bit more than needed, as
// 1. Intel CPUs have "processor order", i.e. writes appear to external
// devices in program order, so a simple final write should be sufficient
// 2. if it is a PCI GART, bus snooping should provide cache coherence
// 3. this function is a no-op :(
clear_caches( gart->GATT.ptr, num_pages * sizeof( uint32 ),
B_FLUSH_DCACHE );
// back to real live - some chipsets have write buffers that
// proove all previous assumptions wrong
// (don't know whether this really helps though)
asm volatile ( "wbinvd" ::: "memory" );
return B_OK;
}
// destroy GART buffer
static void destroyGARTBuffer( GART_info *gart )
{
if( gart->buffer.area > 0 )
delete_area( gart->buffer.area );
if( gart->buffer.unaligned_area > 0 )
delete_area( gart->buffer.unaligned_area );
gart->buffer.area = gart->buffer.unaligned_area = -1;
}
// destroy GATT
static void destroyGATT( GART_info *gart )
{
if( gart->GATT.area > 0 )
delete_area( gart->GATT.area );
gart->GATT.area = -1;
}
// init PCI GART
status_t Radeon_InitPCIGART( device_info *di )
{
status_t result;
result = createGARTBuffer( &di->pci_gart, PCI_GART_SIZE );
if( result < 0 )
goto err1;
result = initGATT( &di->pci_gart );
if( result < 0 )
goto err2;
return B_OK;
err2:
destroyGARTBuffer( &di->pci_gart );
err1:
return result;
}
// cleanup PCI GART
void Radeon_CleanupPCIGART( device_info *di )
{
vuint8 *regs = di->regs;
SHOW_FLOW0( 3, "" );
// perhaps we should wait for FIFO space before messing around with registers, but
// 1. I don't want to add all the sync stuff to the kernel driver
// 2. I doubt that these regs are buffered by FIFO
// but still: in worst case CP has written some commands to register FIFO,
// which can do any kind of nasty things
// disable CP BM
OUTREG( regs, RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIDIS_INDDIS );
// read-back for flushing
INREG( regs, RADEON_CP_CSQ_CNTL );
// disable bus mastering
OUTREGP( regs, RADEON_BUS_CNTL, RADEON_BUS_MASTER_DIS, ~RADEON_BUS_MASTER_DIS );
// disable PCI GART
OUTREGP( regs, RADEON_AIC_CNTL, 0, ~RADEON_PCIGART_TRANSLATE_EN );
destroyGATT( &di->pci_gart );
destroyGARTBuffer( &di->pci_gart );
}

View File

@ -18,7 +18,7 @@
#define PCI_header_type_normal 0
#define PCI_header_type_bridge 1
//#define PCI_header_type_cardbus 2
#define PCI_header_type_cardbus 2
#define PCI_capability_list 0x34 /* Offset of first capability list entry */
#define PCI_cb_capability_list 0x14
@ -60,9 +60,6 @@
#define get_pci(o, s) (*pci_bus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s))
#define set_pci(o, s, v) (*pci_bus->write_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s), (v))
int find_capability( pci_info *pcii, uint8 capability );
void Radeon_Fix_AGP( void );
// show AGP capabilities
static void show_agp_status( uint32 status )

View File

@ -13,30 +13,35 @@
*/
#include "radeon_driver.h"
#include <mmio.h>
#include <bios_regs.h>
#include <config_regs.h>
#include <memcntrl_regs.h>
#include <fp_regs.h>
#include <crtc_regs.h>
#include <radeon_bios.h>
//#include "../common/utils.h"
#include "mmio.h"
#include "bios_regs.h"
#include "config_regs.h"
#include "memcntrl_regs.h"
#include "fp_regs.h"
#include "crtc_regs.h"
#include "radeon_bios.h"
#include "utils.h"
#include <stdio.h>
#include <string.h>
static const char ati_rom_sig[] = "761295520";
static const char *radeon_sig[] = {
"RG6", // r200
"RADEON", // r100
"RV100", // rv100
"U1", // rs100 (IGP320M)
"M6", // mobile version of r100
// probably an M6P;
// anyway - this is the card I wrote this driver for!
// (perhaps ATI tries to make the card incompatible to standard drivers)
"P6",
"RV200", // rv200
"RV100", // rv100
"M7", // m7
"RG6", // r200 (according to spec)
"RS200", // rs200
"R200", // r200 (8500 LE)
"R200AGP", // Fire GL E1
"M9" // guess: m9
"RV250", // rv250 R9100
"V280", // RV280 R9200
"R300", // R300 R9500 / R9700
@ -44,64 +49,69 @@ static const char *radeon_sig[] = {
"R360", // R360 R9800 XT
"V350", // RV350 R9600
"V360", // RV350 R9600 XT :guess
"M9" // guess: m9
};
void Radeon_DetectRAM( device_info *di );
// find address of ROM
// find address of ROM;
// this code is really nasty as maintaining the radeon signatures
// is almost impossible (the signatures provided by ATI are always out-dated);
// further, if there is more then one card built into the computer, we
// may detect the wrong BIOS!
// we have two possible solutions:
// 1. use the PCI location as stored in BIOS
// 2. verify the IO-base address as stored in BIOS
// I have no clue how these values are _written_ into the BIOS, and
// unfortunately, every BIOS does the detection in a different way,
// so I'm not sure which is the _right_ way of doing it
static char *Radeon_FindRom( rom_info *ri )
{
uint32 segstart;
char *rom_base;
uint8 *rom_base;
char *rom;
int stage;
int i,j;
for( segstart = 0x000c0000; segstart < 0x000f0000; segstart += 0x00001000 ) {
stage = 1;
bool found = false;
// find ROM
rom_base = ri->bios_ptr + segstart - 0xc0000;
if( *rom_base == 0x55 && ((*(rom_base + 1)) & 0xff) == 0xaa )
stage = 2;
if (stage != 2)
if( rom_base[0] != 0x55 || rom_base[1] != 0xaa )
continue;
// find signature of ATI
rom = rom_base;
for( i = 0; i < 128 - (int)strlen( ati_rom_sig ) && stage != 3; i++ ) {
if( ati_rom_sig[0] == *rom ) {
if( strncmp(ati_rom_sig, rom, strlen( ati_rom_sig )) == 0 )
stage = 3;
found = false;
for( i = 0; i < 128 - strlen( ati_rom_sig ); i++ ) {
if( ati_rom_sig[0] == rom_base[i] ) {
if( strncmp(ati_rom_sig, rom_base + i, strlen( ati_rom_sig )) == 0 ) {
found = true;
break;
}
}
rom++;
}
if( stage != 3 )
if( !found )
continue;
// find signature of card
rom = rom_base;
found = false;
for( i = 0; (i < 512) && (stage != 4); i++ ) {
for( j = 0; j < (int)sizeof( radeon_sig ) / (int)sizeof( radeon_sig[0] ); j++ ) {
if( radeon_sig[j][0] == *rom ) {
if( strncmp( radeon_sig[j], rom, strlen( radeon_sig[j] )) == 0 ) {
for( i = 0; i < 512; i++ ) {
for( j = 0; j < sizeof( radeon_sig ) / sizeof( radeon_sig[0] ); j++ ) {
if( radeon_sig[j][0] == rom_base[i] ) {
if( strncmp( radeon_sig[j], rom_base + i, strlen( radeon_sig[j] )) == 0 ) {
SHOW_INFO( 2, "Signature: %s", radeon_sig[j] );
stage = 4;
found = true;
break;
}
}
}
rom++;
}
if( stage != 4 )
if( !found )
continue;
SHOW_INFO( 2, "found ROM @0x%lx", segstart );
@ -113,8 +123,8 @@ static char *Radeon_FindRom( rom_info *ri )
}
// PLL info is stored in ROM, probably to easily replace it
// and thus produce cards with different timings
// PLL info is stored in ROM, probably it's too easy to replace it
// and thus they produce cards with different timings
static void Radeon_GetPLLInfo( device_info *di )
{
uint8 *bios_header;
@ -136,6 +146,7 @@ static void Radeon_GetPLLInfo( device_info *di )
di->pll.min_pll_freq, di->pll.max_pll_freq );
}
/*
const char *Mon2Str[] = {
"N/C",
"CRT",
@ -143,10 +154,11 @@ const char *Mon2Str[] = {
"Laptop flatpanel",
"DVI (flatpanel)",
"secondary DVI (flatpanel) - unsupported",
"Composite TV - unsupported",
"S-Video out - unsupported"
};
"Composite TV",
"S-Video out"
};*/
/*
// ask BIOS what kind of monitor is connected to each port
static void Radeon_GetMonType( device_info *di )
{
@ -159,53 +171,57 @@ static void Radeon_GetMonType( device_info *di )
if (di->has_crtc2) {
tmp = INREG( di->regs, RADEON_BIOS_4_SCRATCH );
// ordering of "if"s is important are multiple
// ordering of "if"s is important as multiple
// devices can be concurrently connected to one port
// (like both a CRT and a TV)
// primary port
// having flat-panel support is most important
if (tmp & 0x08)
di->disp_type[0] = dt_dvi_1;
di->disp_type[0] = dt_dvi;
else if (tmp & 0x4)
di->disp_type[0] = dt_lvds;
else if (tmp & 0x200)
di->disp_type[0] = dt_crt_1;
di->disp_type[0] = dt_tv_crt;
else if (tmp & 0x10)
di->disp_type[0] = dt_ctv;
else if (tmp & 0x20)
di->disp_type[0] = dt_stv;
// secondary port
if (tmp & 0x2)
di->disp_type[1] = dt_crt_2;
else if (tmp & 0x800)
di->disp_type[1] = dt_dvi_2;
else if (tmp & 0x400)
// this is unlikely - I only know about one LVDS unit
di->disp_type[1] = dt_lvds;
else if (tmp & 0x1000)
// having TV-Out support is more important then CRT support
// (CRT gets signal anyway)
if (tmp & 0x1000)
di->disp_type[1] = dt_ctv;
else if (tmp & 0x2000)
di->disp_type[1] = dt_stv;
else if (tmp & 0x2)
di->disp_type[1] = dt_crt;
else if (tmp & 0x800)
di->disp_type[1] = dt_dvi_ext;
else if (tmp & 0x400)
// this is unlikely - I only know about one LVDS unit
di->disp_type[1] = dt_lvds;
} else {
// regular Radeon
// TBD: no TV-Out detection
di->disp_type[0] = dt_none;
tmp = INREG( di->regs, RADEON_FP_GEN_CNTL);
if( tmp & RADEON_FP_EN_TMDS )
di->disp_type[0] = dt_dvi_1;
di->disp_type[0] = dt_dvi;
else
di->disp_type[0] = dt_crt_1;
di->disp_type[0] = dt_crt;
}
SHOW_INFO( 1, "BIOS reports %s on primary and %s on secondary port",
Mon2Str[di->disp_type[0]], Mon2Str[di->disp_type[1]]);
// remove unsupported devices
if( di->disp_type[0] >= dt_dvi_2 )
if( di->disp_type[0] >= dt_dvi_ext )
di->disp_type[0] = dt_none;
if( di->disp_type[1] >= dt_dvi_2 )
if( di->disp_type[1] >= dt_dvi_ext )
di->disp_type[1] = dt_none;
// HACK: overlays can only be shown on first CRTC;
@ -213,8 +229,8 @@ static void Radeon_GetMonType( device_info *di )
// second port to first CRTC (proper signal routing
// is hopefully done by BIOS)
if( di->has_crtc2 ) {
if( di->disp_type[0] == dt_none && di->disp_type[1] == dt_crt_2 ) {
di->disp_type[0] = dt_crt_1;
if( di->disp_type[0] == dt_none && di->disp_type[1] == dt_crt ) {
di->disp_type[0] = dt_crt;
di->disp_type[1] = dt_none;
}
}
@ -222,7 +238,7 @@ static void Radeon_GetMonType( device_info *di )
SHOW_INFO( 1, "Effective routing: %s on primary and %s on secondary port",
Mon2Str[di->disp_type[0]], Mon2Str[di->disp_type[1]]);
}
*/
// get flat panel info (does only make sense for Laptops
// with integrated display, but looking for it doesn't hurt,
@ -302,46 +318,14 @@ static bool Radeon_GetBIOSDFPInfo( device_info *di )
static void Radeon_RevEnvDFPSize( device_info *di )
{
vuint8 *regs = di->regs;
/* uint32 r;
// take a look at flat_panel.c of the accelerant how register values
// are calculated - this is the inverse function
r = INREG( regs, RADEON_FP_VERT_STRETCH );
if( (r & RADEON_VERT_STRETCH_BLEND) == 0 ) {
di->fp_info.panel_yres =
((r & RADEON_VERT_PANEL_SIZE) >> RADEON_VERT_PANEL_SHIFT) + 1;
} else {
uint32 v_total = (INREG( regs, RADEON_FP_CRTC_V_TOTAL_DISP )
>> RADEON_FP_CRTC_V_DISP_SHIFT) + 1;
SHOW_INFO( 2, "stretched mode: v_total=%d", v_total );
di->fp_info.panel_yres =
(v_total * FIX_SCALE * RADEON_VERT_STRETCH_RATIO_MAX /
(r & RADEON_VERT_STRETCH_RATIO_MASK) + FIX_SCALE / 2) >> FIX_SHIFT;
// seems to be a BIOS bug - vertical size is 1 point too small
// (checked by re-calculating stretch factor)
++di->fp_info.panel_yres;
}
r = INREG( regs, RADEON_FP_HORZ_STRETCH );
if( (r & RADEON_HORZ_STRETCH_BLEND) == 0 ) {
di->fp_info.panel_xres =
(((r & RADEON_HORZ_PANEL_SIZE) >> RADEON_HORZ_PANEL_SHIFT) + 1) * 8;
} else {
uint32 h_total = ((INREG( regs, RADEON_FP_CRTC_H_TOTAL_DISP )
>> RADEON_FP_CRTC_H_DISP_SHIFT) + 1) * 8;
SHOW_INFO( 2, "stretched mode: h_total=%d", h_total );
di->fp_info.panel_xres =
(h_total * FIX_SCALE * RADEON_HORZ_STRETCH_RATIO_MAX /
(r & RADEON_HORZ_STRETCH_RATIO_MASK) + FIX_SCALE / 2) >> FIX_SHIFT;
}*/
di->fp_info.panel_yres =
((INREG( regs, RADEON_FP_VERT_STRETCH ) & RADEON_VERT_PANEL_SIZE)
>> RADEON_VERT_PANEL_SHIFT) + 1;
>> RADEON_VERT_PANEL_SIZE_SHIFT) + 1;
di->fp_info.panel_xres =
(((INREG( regs, RADEON_FP_HORZ_STRETCH ) & RADEON_HORZ_PANEL_SIZE)
>> RADEON_HORZ_PANEL_SHIFT) + 1) * 8;
>> RADEON_HORZ_PANEL_SIZE_SHIFT) + 1) * 8;
SHOW_INFO( 2, "detected panel size from registers: %dx%d",
di->fp_info.panel_xres, di->fp_info.panel_yres);
@ -373,7 +357,7 @@ static void Radeon_RevEnvDFPTiming( device_info *di )
((r & RADEON_FP_H_SYNC_WID_MASK)
>> RADEON_FP_H_SYNC_WID_SHIFT);
// TBD: this seems to be wrong
// (BIOS tells 112, this calculation leads to 24!)
// (my BIOS tells 112, this calculation leads to 24!)
di->fp_info.h_sync_width *= 8;
r = INREG( regs, RADEON_FP_CRTC_V_TOTAL_DISP );
@ -389,7 +373,6 @@ static void Radeon_RevEnvDFPTiming( device_info *di )
>> RADEON_FP_V_SYNC_WID_SHIFT)/* + 1*/;
// standard CRTC
r = INREG( regs, RADEON_CRTC_H_TOTAL_DISP );
a = (r & RADEON_CRTC_H_TOTAL);
b = (r & RADEON_CRTC_H_DISP) >> RADEON_CRTC_H_DISP_SHIFT;
@ -421,6 +404,7 @@ static void Radeon_RevEnvDFPTiming( device_info *di )
}
/*
// get everything in terms of monitors connected to the card
static void Radeon_GetBIOSMon( device_info *di )
{
@ -433,8 +417,7 @@ static void Radeon_GetBIOSMon( device_info *di )
// we assume that the only fp port is combined with standard port 0
di->fp_info.disp_type = di->disp_type[0];
if( di->disp_type[0] == dt_dvi_1 || di->disp_type[0] == dt_lvds )
{
if( di->is_mobility ) {
// there is a flat panel - get info about it
Radeon_GetBIOSDFPInfo( di );
@ -452,14 +435,49 @@ static void Radeon_GetBIOSMon( device_info *di )
SHOW_INFO( 2, "pixel_clock=%d", di->fp_info.dot_clock );
}
}
*/
// get info about Laptop flat panel
static void Radeon_GetFPData( device_info *di )
{
// reset all Flat Panel Info;
// it gets filled out step by step, and this way we know what's still missing
memset( &di->fp_info, 0, sizeof( di->fp_info ));
// we only use BIOS for Laptop flat panels
if( !di->is_mobility )
return;
// ask BIOS about flat panel spec
Radeon_GetBIOSDFPInfo( di );
// if BIOS doesn't know, ask the registers
if( di->fp_info.panel_xres == 0 || di->fp_info.panel_yres == 0)
Radeon_RevEnvDFPSize( di );
if( di->fp_info.h_blank == 0 || di->fp_info.v_blank == 0)
Radeon_RevEnvDFPTiming( di );
SHOW_INFO( 2, "h_disp=%d, h_blank=%d, h_over_plus=%d, h_sync_width=%d",
di->fp_info.panel_xres, di->fp_info.h_blank, di->fp_info.h_over_plus, di->fp_info.h_sync_width );
SHOW_INFO( 2, "v_disp=%d, v_blank=%d, v_over_plus=%d, v_sync_width=%d",
di->fp_info.panel_yres, di->fp_info.v_blank, di->fp_info.v_over_plus, di->fp_info.v_sync_width );
SHOW_INFO( 2, "pixel_clock=%d", di->fp_info.dot_clock );
}
// detect amount of graphics memory
void Radeon_DetectRAM( device_info *di )
{
vuint8 *regs = di->regs;
di->local_mem_size = INREG( regs, RADEON_CONFIG_MEMSIZE ) & RADEON_CONFIG_MEMSIZE_MASK;
if( !di->is_igp )
di->local_mem_size = INREG( regs, RADEON_CONFIG_MEMSIZE ) & RADEON_CONFIG_MEMSIZE_MASK;
else {
uint32 tom;
tom = INREG( regs, RADEON_GC_NB_TOM );
di->local_mem_size = ((tom >> 16) + 1 - (tom & 0xffff)) << 16;
}
// some production boards of m6 will return 0 if it's 8 MB
if( di->local_mem_size == 0 )
@ -500,11 +518,11 @@ void Radeon_DetectRAM( device_info *di )
SHOW_INFO( 1, "%ld MB %s found", di->local_mem_size / 1024 / 1024,
di->ram_type );
if( di->local_mem_size > 64 * 1024 * 1024 ) {
/* if( di->local_mem_size > 64 * 1024 * 1024 ) {
di->local_mem_size = 64 * 1024 * 1024;
SHOW_INFO0( 1, "restricted to 64 MB" );
}
}*/
}
@ -512,7 +530,7 @@ void Radeon_DetectRAM( device_info *di )
// (as we need BIOS for further info we have to make sure we use the right one)
status_t Radeon_MapBIOS( pci_info *pcii, rom_info *ri )
{
char buffer[B_OS_NAME_LENGTH];
char buffer[100];
sprintf(buffer, "%04X_%04X_%02X%02X%02X bios",
pcii->vendor_id, pcii->device_id,
@ -525,13 +543,20 @@ status_t Radeon_MapBIOS( pci_info *pcii, rom_info *ri )
// device name), thus you couldn't choose in BIOS which card
// to use; checking the legacy location ensures that the card is
// only detected if it's the primary card
ri->bios_area = map_physical_memory( buffer, (void *)0xc0000,
0x40000, B_ANY_KERNEL_ADDRESS, B_READ_AREA, (void **)&ri->bios_ptr );
ri->phys_address = 0xc0000;
ri->size = 0x40000;
ri->bios_area = map_physical_memory( buffer, (void *)ri->phys_address,
ri->size, B_ANY_KERNEL_ADDRESS, B_READ_AREA, (void **)&ri->bios_ptr );
if( ri->bios_area < 0 )
return ri->bios_area;
ri->rom_ptr = Radeon_FindRom( ri );
// on success, adjust physical address to found ROM
if( ri->rom_ptr != NULL )
ri->phys_address += ri->rom_ptr - ri->bios_ptr;
return ri->rom_ptr != NULL ? B_OK : B_ERROR;
}
@ -560,7 +585,7 @@ status_t Radeon_ReadBIOSData( device_info *di )
goto err1;
Radeon_GetPLLInfo( di );
Radeon_GetBIOSMon( di );
Radeon_GetFPData( di );
Radeon_DetectRAM( di );
Radeon_UnmapDevice( di );

View File

@ -68,8 +68,8 @@
// RV280
#define DEVICE_ID_RADEON_Ya_ 0x5960
#define DEVICE_ID_RADEON_Ya 0x5961
#define DEVICE_ID_RADEON_Yd 0x5964
#define DEVICE_ID_RADEON_Ya 0x5961
#define DEVICE_ID_RADEON_Yd 0x5964
// r300
#define DEVICE_ID_RADEON_ND 0x4e44
@ -97,11 +97,19 @@
#define DEVICE_ID_RADEON_NH 0x4e48
#define DEVICE_ID_RADEON_NI 0x4e49
// Mobility Fire GL T2 - any idea about the chip?
#define DEVICE_ID_RADEON_NT 0x4e54
// r360
#define DEVICE_ID_RADEON_NJ 0x4e4a
// rs100
#define DEVICE_ID_IGP320M 0x4336
// rs200
#define DEVICE_ID_RADEON_C7 0x4337
#define DEVICE_ID_RADEON_A7 0x4137
typedef struct {
uint16 device_id;
radeon_type asic;
@ -123,17 +131,22 @@ RadeonDevice radeon_device_list[] = {
// mobility version of original Radeon (based on VE), now called M6
{ DEVICE_ID_RADEON_LY, rt_m6, "Radeon Mobility" },
{ DEVICE_ID_RADEON_LZ, rt_m6, "Radeon Mobility M6 LZ" },
// not sure about that: ROM signature is "RADEON" which means r100
{ DEVICE_ID_RADEON_NT, rt_m6, "Radeon Mobility FireGL T2" },
// rs100 (integrated Radeon, seems to be a Radeon VE)
{ DEVICE_ID_IGP320M, rt_rs100, "IGP320M" },
// RV200 (dual CRT)
{ DEVICE_ID_RADEON_QW, rt_rv200, "Radeon 7500 / ALL-IN-WONDER Radeon 7500" },
{ DEVICE_ID_RADEON_QX, rt_rv200, "Radeon 7500 QX" },
// R200 mobility (based on RV200)
// M7 (based on RV200)
{ DEVICE_ID_RADEON_LW, rt_m7, "Radeon Mobility 7500" },
{ DEVICE_ID_RADEON_LX, rt_m7, "Radeon Mobility 7500 GL" },
// R200
{ DEVICE_ID_RADEON_QH, rt_r200, "Radeon 8500 QH" },
{ DEVICE_ID_RADEON_QH, rt_r200, "ATI Fire GL E1" }, // chip type: fgl8800
{ DEVICE_ID_RADEON_QI, rt_r200, "Radeon 8500 QI" },
{ DEVICE_ID_RADEON_QJ, rt_r200, "Radeon 8500 QJ" },
{ DEVICE_ID_RADEON_QK, rt_r200, "Radeon 8500 QK" },
@ -160,9 +173,9 @@ RadeonDevice radeon_device_list[] = {
// RV280
// the naming scheme can't properly handle this id
{ DEVICE_ID_RADEON_Ya_, rt_rv250, "Radeon 9200" },
{ DEVICE_ID_RADEON_Ya, rt_rv250, "Radeon 9200" },
{ DEVICE_ID_RADEON_Yd, rt_rv250, "Radeon 9200 SE" },
{ DEVICE_ID_RADEON_Ya_, rt_rv280, "Radeon 9200" },
{ DEVICE_ID_RADEON_Ya, rt_rv280, "Radeon 9200" },
{ DEVICE_ID_RADEON_Yd, rt_rv280, "Radeon 9200 SE" },
// R300
{ DEVICE_ID_RADEON_ND, rt_r300, "Radeon 9700 ND" },
@ -178,8 +191,8 @@ RadeonDevice radeon_device_list[] = {
// RV350
{ DEVICE_ID_RADEON_AP, rt_rv350, "Radeon 9600 AP" },
{ DEVICE_ID_RADEON_AQ, rt_rv350, "Radeon 9600 AQ" },
{ DEVICE_ID_RADEON_NO, rt_rv350, "Radeon Mobility 9600 Pro Turbo" },
{ DEVICE_ID_RADEON_NS, rt_rv350, "Mobility FireGL T2" },
{ DEVICE_ID_RADEON_NO, rt_rv350, "Radeon 9600 Pro" },
{ DEVICE_ID_RADEON_NS, rt_rv350, "Mobility FireGL T2" },
// RV360 (probably minor revision of rv350)
{ DEVICE_ID_RADEON_AR, rt_rv360, "Radeon 9600 AR" },
@ -192,7 +205,12 @@ RadeonDevice radeon_device_list[] = {
// R360 (probably minor revision of r350)
{ DEVICE_ID_RADEON_NJ, rt_r360, "Radeon 9800 XT" },
{ DEVICE_ID_IGP320M, rt_ve, "Radeon IGP 320M" },
// rs100 (aka IGP)
{ DEVICE_ID_IGP320M, rt_rs100, "Radeon IGP 320M" },
// rs200 (aka IGP)
{ DEVICE_ID_RADEON_C7, rt_rs200, "IGP330M/340M/350M (U2) 4337" },
{ DEVICE_ID_RADEON_A7, rt_rs200, "IGP 340" },
{ 0, 0, NULL }
};
@ -254,43 +272,34 @@ done:
}
// !extend this array whenever a new ASIC is a added!
static bool has_crtc2[] =
static struct {
const char *name; // name of ASIC
tv_chip_type tv_chip; // TV-Out chip (if any)
bool has_crtc2; // has second CRTC
bool is_mobility; // mobility chip
bool has_vip; // has VIP/I2C
bool is_igp; // integrated graphics
} asic_properties[] =
{
false, // only original Radeons have one crtc only
false,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true
{ "r100", tc_external_rt1, false, false, true, false }, // only original Radeons have one crtc only
{ "ve", tc_internal_rt1, true, false, true, false },
{ "m6", tc_internal_rt1, true, true, false, false },
{ "rs100", tc_internal_rt1, true, true, false, true },
{ "rv200", tc_internal_rt2, true, false, true, false },
{ "m7", tc_internal_rt1, true, true, false, false },
{ "rs200", tc_internal_rt1, true, true, false, true },
{ "r200", tc_external_rt1, true, false, true, false }, // r200 has external TV-Out encoder
{ "rv250", tc_internal_rt2, true, false, true, false },
{ "rv280", tc_internal_rt2, true, false, true, false },
{ "m9", tc_internal_rt2, true, true, true, false },
{ "r300", tc_internal_rt2, true, false, true, false },
{ "r300_4p",tc_internal_rt2, true, false, true, false },
{ "rv350", tc_internal_rt2, true, false, true, false },
{ "rv360", tc_internal_rt2, true, false, true, false },
{ "r350", tc_internal_rt2, true, false, true, false },
{ "r360", tc_internal_rt2, true, false, true, false }
};
static const char *asic_name[] =
{
"r100",
"ve",
"m6",
"rv200",
"m7",
"r200",
"rv250",
"rv280",
"m9",
"r300",
"r300_4p",
"rv350",
"rv360",
"r350",
"r360",
};
// get next supported device
static bool probeDevice( device_info *di )
@ -309,8 +318,12 @@ static bool probeDevice( device_info *di )
if (device->device_id != di->pcii.device_id )
continue;
di->has_crtc2 = has_crtc2[device->asic];
di->num_heads = asic_properties[device->asic].has_crtc2 ? 2 : 1;
di->tv_chip = asic_properties[device->asic].tv_chip;
di->asic = device->asic;
di->is_mobility = asic_properties[device->asic].is_mobility;
di->has_vip = asic_properties[device->asic].has_vip;
di->is_igp = asic_properties[device->asic].is_igp;
if( Radeon_MapBIOS( &di->pcii, &di->rom ) != B_OK )
// give up checking this device - no BIOS, no fun
@ -324,13 +337,21 @@ static bool probeDevice( device_info *di )
// we don't need BIOS any more
Radeon_UnmapBIOS( &di->rom );
SHOW_INFO( 0, "found %s; ASIC: %s", device->name, asic_name[device->asic] );
SHOW_INFO( 0, "found %s; ASIC: %s", device->name, asic_properties[device->asic].name );
sprintf(di->name, "graphics/%04X_%04X_%02X%02X%02X",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function);
SHOW_FLOW( 3, "making /dev/%s", di->name );
// we always publish it as a video grabber; we should check for Rage
// Theater, but the corresponding code (vip.c) needs a fully initialized
// driver, and this is too much hazzly, so we leave it to the media add-on
// to verify that the card really supports video-in
sprintf(di->video_name, "video/radeon/%04X_%04X_%02X%02X%02X",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function);
di->is_open = 0;
di->shared_area = -1;
di->si = NULL;
@ -360,7 +381,8 @@ void Radeon_ProbeDevices( void )
break;
if( probeDevice( di )) {
devices->device_names[count] = di->name;
devices->device_names[2*count] = di->name;
devices->device_names[2*count+1] = di->video_name;
di++;
count++;
}
@ -369,7 +391,7 @@ void Radeon_ProbeDevices( void )
}
devices->count = count;
devices->device_names[count] = NULL;
devices->device_names[2*count] = NULL;
SHOW_INFO( 0, "%ld supported devices", count );
}

View File

@ -1,328 +0,0 @@
/*
Copyright (c) 2002, Thomas Kurschel
Part of Radeon kernel driver
DMA initialization/clean-up.
Currently, we use PCI DMA. Changing to AGP would
only affect this file, but AGP-GART is specific to
the chipset of the motherboard, and as DMA is really
overkill for 2D, I cannot bother writing a dozen
of AGP drivers just to gain little extra speedup.
*/
#include "radeon_driver.h"
#include <malloc.h>
#include <image.h>
#include <mmio.h>
#include <buscntrl_regs.h>
#include <memcntrl_regs.h>
#include <cp_regs.h>
#include <string.h>
#if 0
// create actual DMA buffer
static status_t createDMABuffer( DMA_buffer *buffer, size_t size )
{
SHOW_FLOW0( 3, "" );
buffer->size = size = (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
// if this buffer is used for PCI BM, cache snooping
// takes care of syncing memory accesses; if used for AGP,
// we'll have to access via AGP aperture (and mark aperture
// as write-combined) as cache consistency doesn't need to
// be guaranteed
// the specs say that some chipsets do kind of lazy flushing
// so the graphics card may read obsolete data; up to now
// we use PCI only where this shouldn't happen by design;
// if we change to AGP we may tweak the pre-charge time of
// the write buffer pointer
// as some variables in accelerant point directly into
// the DMA buffer, we have to grant access for all apps
buffer->buffer_area = create_area( "Radeon DMA buffer",
&buffer->ptr, B_ANY_KERNEL_ADDRESS,
size, B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA );
if( buffer->buffer_area < 0 ) {
SHOW_ERROR( 1, "cannot create DMA buffer (%s)",
strerror( buffer->buffer_area ));
return buffer->buffer_area;
}
memset( buffer->ptr, 0, size );
return B_OK;
}
#endif
static status_t createDMABuffer( DMA_buffer *buffer, size_t size )
{
physical_entry map[1];
void *unaligned_addr, *aligned_phys;
SHOW_FLOW0( 3, "" );
buffer->size = size = (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
// we allocate an contiguous area having twice the size
// to be able to find an aligned, contiguous range within it;
// the graphics card doesn't care, but the CPU cannot
// make an arbitrary area WC'ed, at least elder ones
// question: is this necessary for a PCI GART because of bus snooping?
buffer->unaligned_area = create_area( "Radeon DMA buffer",
&unaligned_addr, B_ANY_KERNEL_ADDRESS,
2 * size, B_CONTIGUOUS/*B_FULL_LOCK*/, B_READ_AREA | B_WRITE_AREA );
if( buffer->unaligned_area < 0 ) {
SHOW_ERROR( 1, "cannot create DMA buffer (%s)",
strerror( buffer->unaligned_area ));
return buffer->unaligned_area;
}
get_memory_map( unaligned_addr, B_PAGE_SIZE, map, 1 );
aligned_phys =
(void **)(((uint32)map[0].address + size - 1) & ~(size - 1));
SHOW_FLOW( 3, "aligned_phys=%p", aligned_phys );
buffer->buffer_area = map_physical_memory( "Radeon aligned DMA buffer",
aligned_phys,
size, B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
B_READ_AREA | B_WRITE_AREA, &buffer->ptr );
if( buffer->buffer_area < 0 ) {
SHOW_ERROR0( 3, "cannot map buffer with WC" );
buffer->buffer_area = map_physical_memory( "Radeon aligned DMA buffer",
aligned_phys,
size, B_ANY_KERNEL_BLOCK_ADDRESS,
B_READ_AREA | B_WRITE_AREA, &buffer->ptr );
}
if( buffer->buffer_area < 0 ) {
SHOW_ERROR0( 1, "cannot map DMA buffer" );
delete_area( buffer->unaligned_area );
buffer->unaligned_area = -1;
return buffer->buffer_area;
}
memset( buffer->ptr, 0, size );
return B_OK;
}
// init GART (could be used for both PCI and AGP)
static status_t initGART( DMA_buffer *buffer )
{
physical_entry *map;
physical_entry PTB_map[1];
size_t map_count;
int i;
uint32 *gart_entry;
size_t num_pages;
SHOW_FLOW0( 3, "" );
num_pages = (buffer->size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
// GART must be contignuous
buffer->GART_area = create_area( "Radeon GART", (void **)&buffer->GART_ptr,
B_ANY_KERNEL_ADDRESS,
(num_pages * sizeof( uint32 ) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1),
B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA );
if( buffer->GART_area < 0 ) {
SHOW_ERROR( 1, "cannot create GART table (%s)",
strerror( buffer->GART_area ));
return buffer->GART_area;
}
get_memory_map( buffer->GART_ptr, B_PAGE_SIZE, PTB_map, 1 );
buffer->GART_phys = (uint32)PTB_map[0].address;
SHOW_INFO( 3, "GART_ptr=%p, GART_phys=%p", buffer->GART_ptr,
(void *)buffer->GART_phys );
// get address mapping
memset( buffer->GART_ptr, 0, num_pages * sizeof( uint32 ));
map_count = num_pages + 1;
map = malloc( map_count * sizeof( physical_entry ) );
get_memory_map( buffer->ptr, buffer->size, map, map_count );
// the following looks a bit strange as the kernel
// combines successive entries
gart_entry = buffer->GART_ptr;
for( i = 0; i < (int)map_count; ++i ) {
uint32 addr = (uint32)map[i].address;
size_t size = map[i].size;
if( size == 0 )
break;
while( size > 0 ) {
*gart_entry++ = addr;
//SHOW_FLOW( 3, "%lx", *(gart_entry-1) );
addr += ATI_PCIGART_PAGE_SIZE;
size -= ATI_PCIGART_PAGE_SIZE;
}
}
free( map );
if( i == (int)map_count ) {
// this case should never happen
SHOW_ERROR0( 0, "memory map of DMA buffer too large!" );
delete_area( buffer->GART_area );
buffer->GART_area = -1;
return B_ERROR;
}
// this might be a bit more than needed, as
// 1. Intel CPUs have "processor order", i.e. writes appear to external
// devices in program order, so a simple final write should be sufficient
// 2. if it is a PCI GART, bus snooping should provide cache coherence
// 3. this function is a no-op :(
clear_caches( buffer->GART_ptr, num_pages * sizeof( uint32 ),
B_FLUSH_DCACHE );
// back to real live - some chipsets have write buffers that
// proove all previous assumption wrong
asm volatile ( "wbinvd" ::: "memory" );
return B_OK;
}
// destroy DMA buffer
static void destroyDMABuffer( DMA_buffer *buffer )
{
if( buffer->buffer_area >= 0 )
delete_area( buffer->buffer_area );
buffer->buffer_area = -1;
}
// destroy GART
static void destroyGART( DMA_buffer *buffer )
{
if( buffer->unaligned_area >= 0 )
delete_area( buffer->unaligned_area );
if( buffer->GART_area >= 0 )
delete_area( buffer->GART_area );
buffer->GART_area = -1;
}
// initialize DMA (well - we initialize entire memory controller)
status_t Radeon_InitDMA( device_info *di )
{
vuint8 *regs = di->regs;
shared_info *si = di->si;
status_t result;
// any address not covered by frame buffer, PCI GART or AGP aperture
// leads to a direct memory access
// -> this is dangerous, so we make sure entire address space is mapped
// locate PCI GART at top of address space
si->nonlocal_vm_start = -ATI_MAX_PCIGART_PAGES * ATI_PCIGART_PAGE_SIZE;
si->nonlocal_mem_size = ATI_MAX_PCIGART_PAGES * ATI_PCIGART_PAGE_SIZE;
SHOW_INFO( 3, "Non-local memory %lx@%lx (graphics card address)",
si->nonlocal_mem_size, si->nonlocal_vm_start );
// let AGP range overlap with frame buffer to hide it;
// according to spec, frame buffer should win but we better
// choose an unused-area to avoid trouble
// (specs don't talk about overlapping area, let's hope
// the memory controller won't choke if we ever access it)
si->AGP_vm_start = si->nonlocal_vm_start - 0x10000;
si->AGP_vm_size = 0x10000;
result = createDMABuffer( &di->DMABuffer, 0x80000 );
if( result < 0 )
goto err1;
result = initGART( &di->DMABuffer );
if( result < 0 )
goto err2;
SHOW_INFO( 3, "GART=%p", di->DMABuffer.ptr );
si->nonlocal_mem = di->DMABuffer.ptr;
// set PCI GART page-table base address
OUTREG( regs, RADEON_AIC_PT_BASE, di->DMABuffer.GART_phys );
// set address range for PCI address translate
OUTREG( regs, RADEON_AIC_LO_ADDR, si->nonlocal_vm_start );
OUTREG( regs, RADEON_AIC_HI_ADDR, si->nonlocal_vm_start +
di->DMABuffer.size - 1 );
// set AGP address range
OUTREG( regs, RADEON_MC_AGP_LOCATION,
(si->AGP_vm_start & 0xffff0000) |
((si->AGP_vm_start + si->AGP_vm_size - 1) >> 16 ));
// set address range of video memory
// (lower word = begin >> 16
// upper word = end >> 16)
// let it cover all remaining addresses;
// addresses are wrapped
OUTREG( regs, RADEON_MC_FB_LOCATION,
((si->nonlocal_vm_start - 1) & 0xffff0000) |
(0 >> 16) );
// disable AGP
OUTREG( regs, RADEON_AGP_COMMAND, 0 );
// Turn on PCI GART
#if 1
OUTREGP( regs, RADEON_AIC_CNTL, RADEON_PCIGART_TRANSLATE_EN,
~RADEON_PCIGART_TRANSLATE_EN );
#endif
// SHOW_FLOW0( 3, "done" );
return B_OK;
err2:
destroyDMABuffer( &di->DMABuffer );
err1:
return result;
}
// cleanup DMA
void Radeon_CleanupDMA( device_info *di )
{
vuint8 *regs = di->regs;
SHOW_FLOW0( 3, "" );
// perhaps we should wait for FIFO space before messing around with registers, but
// 1. I don't want to add all the sync stuff to the kernel driver
// 2. I doubt that these regs are buffered by FIFO
// disable CP BM
OUTREG( regs, RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIDIS_INDDIS );
// disable bus mastering
OUTREGP( regs, RADEON_BUS_CNTL, RADEON_BUS_MASTER_DIS, ~RADEON_BUS_MASTER_DIS );
// disable PCI GART
OUTREGP( regs, RADEON_AIC_CNTL, 0, ~RADEON_PCIGART_TRANSLATE_EN );
destroyGART( &di->DMABuffer );
destroyDMABuffer( &di->DMABuffer );
}

View File

@ -8,21 +8,17 @@
*/
#include "radeon_driver.h"
#ifdef ENABLE_LOGGING
#include "log_coll.h"
#endif
#include <OS.h>
#include <malloc.h>
#include <graphic_driver.h>
#include <stdio.h>
#include <string.h>
#include <mmio.h>
#include <version.h>
#include "mmio.h"
#include "version.h"
// tell the kernel what revision of the driver API we support
//int32 api_version = 2;
int32 api_version = B_CUR_DRIVER_API_VERSION; // apsed, was 2, is 2 in R5
int32 api_version = 2;
static status_t open_hook( const char *name, uint32 flags, void **cookie );
@ -61,6 +57,8 @@ status_t init_hardware( void )
// public function: init driver
status_t init_driver( void )
{
SHOW_FLOW0( 3, "" );
if( get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK )
return B_ERROR;
@ -71,7 +69,7 @@ status_t init_driver( void )
return B_ERROR;
}
INIT_BEN( "Radeon Kernel", devices->kernel);
(void)INIT_BEN( devices->kernel, "Radeon Kernel" );
Radeon_ProbeDevices();
return B_OK;
@ -81,6 +79,7 @@ status_t init_driver( void )
// public function: uninit driver
void uninit_driver( void )
{
SHOW_FLOW0( 3, "" );
DELETE_BEN( devices->kernel );
free( devices );
@ -126,7 +125,7 @@ static status_t open_hook( const char *name, uint32 flags, void **cookie )
strcmp(name, devices->device_names[index] ) != 0 )
index++;
di = &(devices->di[index]);
di = &(devices->di[index/2]);
ACQUIRE_BEN( devices->kernel );
@ -173,11 +172,17 @@ static status_t free_hook( void *dev )
{
device_info *di = (device_info *)dev;
SHOW_FLOW0( 3, "" );
SHOW_FLOW0( 0, "" );
ACQUIRE_BEN( devices->kernel );
mem_freetag( di->local_memmgr, dev );
mem_freetag( di->memmgr[mt_local], dev );
if( di->memmgr[mt_PCI] )
mem_freetag( di->memmgr[mt_PCI], dev );
if( di->memmgr[mt_AGP] )
mem_freetag( di->memmgr[mt_AGP], dev );
if( di->is_open == 1 )
Radeon_LastClose( di );
@ -199,8 +204,7 @@ static status_t control_hook( void *dev, uint32 msg, void *buf, size_t len )
// needed by app_server to load accelerant
case B_GET_ACCELERANT_SIGNATURE: {
char *sig = (char *)buf;
//strcpy(sig, "radeon2.accelerant");
strcpy(sig, "radeon.accelerant");
strcpy(sig, "radeon2.accelerant");
result = B_OK;
} break;
@ -226,22 +230,124 @@ static status_t control_hook( void *dev, uint32 msg, void *buf, size_t len )
} break;
// graphics mem manager
case RADEON_ALLOC_LOCAL_MEM: {
radeon_alloc_local_mem *am = (radeon_alloc_local_mem *)buf;
case RADEON_ALLOC_MEM: {
radeon_alloc_mem *am = (radeon_alloc_mem *)buf;
memory_type_e memory_type;
if( am->magic == RADEON_PRIVATE_DATA_MAGIC )
result = mem_alloc( di->local_memmgr, am->size, dev, &am->handle, &am->fb_offset );
if( am->magic != RADEON_PRIVATE_DATA_MAGIC )
break;
if( am->memory_type > mt_last )
break;
memory_type = am->memory_type == mt_nonlocal ? di->si->nonlocal_type : am->memory_type;
result = mem_alloc( di->memmgr[memory_type], am->size, am->global ? 0 : dev, &am->handle, &am->offset );
} break;
case RADEON_FREE_LOCAL_MEM: {
radeon_free_local_mem *fm = (radeon_free_local_mem *)buf;
if( fm->magic == RADEON_PRIVATE_DATA_MAGIC )
result = mem_free( di->local_memmgr, fm->handle, dev );
case RADEON_FREE_MEM: {
radeon_free_mem *fm = (radeon_free_mem *)buf;
memory_type_e memory_type;
if( fm->magic != RADEON_PRIVATE_DATA_MAGIC )
break;
if( fm->memory_type > mt_last )
break;
memory_type = fm->memory_type == mt_nonlocal ? di->si->nonlocal_type : fm->memory_type;
result = mem_free( di->memmgr[memory_type], fm->handle, fm->global ? 0 : dev );
} break;
case RADEON_WAITFORIDLE: {
radeon_wait_for_idle *wfi = (radeon_wait_for_idle *)buf;
// interface to log data
if( wfi->magic != RADEON_PRIVATE_DATA_MAGIC )
break;
Radeon_WaitForIdle( di, true, wfi->keep_lock );
result = B_OK;
} break;
case RADEON_RESETENGINE: {
radeon_no_arg *na = (radeon_no_arg *)buf;
if( na->magic != RADEON_PRIVATE_DATA_MAGIC )
break;
ACQUIRE_BEN( di->si->cp.lock );
Radeon_ResetEngine( di );
RELEASE_BEN( di->si->cp.lock );
result = B_OK;
} break;
case RADEON_VIPREAD: {
radeon_vip_read *vr = (radeon_vip_read *)buf;
if( vr->magic != RADEON_PRIVATE_DATA_MAGIC )
break;
result = Radeon_VIPRead( di, vr->channel, vr->address, &vr->data ) ?
B_OK : B_ERROR;
} break;
case RADEON_VIPWRITE: {
radeon_vip_write *vw = (radeon_vip_write *)buf;
if( vw->magic != RADEON_PRIVATE_DATA_MAGIC )
break;
result = Radeon_VIPWrite( di, vw->channel, vw->address, vw->data ) ?
B_OK : B_ERROR;
} break;
case RADEON_FINDVIPDEVICE: {
radeon_find_vip_device *fvd = (radeon_find_vip_device *)buf;
if( fvd->magic != RADEON_PRIVATE_DATA_MAGIC )
break;
fvd->channel = Radeon_FindVIPDevice( di, fvd->device_id );
result = B_OK;
} break;
case RADEON_WAIT_FOR_CAP_IRQ: {
radeon_wait_for_cap_irq *wvc = (radeon_wait_for_cap_irq *)buf;
if( wvc->magic != RADEON_PRIVATE_DATA_MAGIC )
break;
// restrict wait time to 1 sec to get not stuck here in kernel
result = acquire_sem_etc( di->cap_sem, 1, B_RELATIVE_TIMEOUT,
min( wvc->timeout, 1000000 ));
if( result == B_OK ) {
cpu_status prev_irq_state = disable_interrupts();
acquire_spinlock( &di->cap_spinlock );
wvc->timestamp = di->cap_timestamp;
wvc->int_status = di->cap_int_status;
wvc->counter = di->cap_counter;
release_spinlock( &di->cap_spinlock );
restore_interrupts( prev_irq_state );
}
} break;
case RADEON_DMACOPY: {
radeon_dma_copy *dc = (radeon_dma_copy *)buf;
if( dc->magic != RADEON_PRIVATE_DATA_MAGIC )
break;
result = Radeon_DMACopy( di, dc->src, dc->target, dc->size, dc->lock_mem, dc->contiguous );
} break;
#ifdef ENABLE_LOGGING
#ifdef LOG_INCLUDE_STARTUP
// interface to log data
case RADEON_GET_LOG_SIZE:
*(uint32 *)buf = log_getsize( di->si->log );
result = B_OK;
@ -250,26 +356,13 @@ static status_t control_hook( void *dev, uint32 msg, void *buf, size_t len )
case RADEON_GET_LOG_DATA:
log_getcopy( di->si->log, buf, ((uint32 *)buf)[0] );
result = B_OK;
break;
break;
#endif
#endif
// interface to i2c-bus
case RADEON_SET_I2C_SIGNALS: {
radeon_getset_i2c *data = (radeon_getset_i2c *)buf;
if( data->magic == RADEON_PRIVATE_DATA_MAGIC ) {
result = B_OK;
OUTREG( di->regs, data->port, data->value );
}
break; }
case RADEON_GET_I2C_SIGNALS: {
radeon_getset_i2c *data = (radeon_getset_i2c *)buf;
if( data->magic == RADEON_PRIVATE_DATA_MAGIC ) {
result = B_OK;
data->value = INREG( di->regs, data->port );
}
break; }
}
if( result == B_DEV_INVALID_IOCTL )
SHOW_ERROR( 3, "Invalid ioctl call: code=0x%lx", msg );
return result;
}

View File

@ -16,8 +16,8 @@
#include <PCI.h>
#include <stdio.h>
#include <dac_regs.h>
#include <mmio.h>
#include "dac_regs.h"
#include "mmio.h"
// helper macros for easier PCI access
#define get_pci(o, s) (*pci_bus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s))
@ -32,7 +32,7 @@ status_t Radeon_MapDevice( device_info *di, bool mmio_only )
// register map in PCI range 2
int regs = 2;
int fb = 0;
char buffer[B_OS_NAME_LENGTH];
char buffer[100];
shared_info *si = di->si;
uint32 tmp;
pci_info *pcii = &(di->pcii);
@ -41,7 +41,7 @@ status_t Radeon_MapDevice( device_info *di, bool mmio_only )
SHOW_FLOW( 3, "device: %02X%02X%02X",
di->pcii.bus, di->pcii.device, di->pcii.function );
si->regs_area = si->fb_area = 0;
si->ROM_area = si->regs_area = si->memory[mt_local].area = 0;
// enable memory mapped IO and frame buffer
// also, enable bus mastering (some BIOSes seem to
@ -66,13 +66,33 @@ status_t Radeon_MapDevice( device_info *di, bool mmio_only )
(void *) di->pcii.u.h0.base_registers[regs],
di->pcii.u.h0.base_register_sizes[regs],
B_ANY_KERNEL_ADDRESS,
0,
/*// for "poke" debugging
B_READ_AREA + B_WRITE_AREA*/0,
(void **)&(di->regs));
if( si->regs_area < 0 )
return si->regs_area;
// that's all during detection as we have no clue about ROM or
// frame buffer at this point
if( mmio_only )
return B_OK;
// ROM must be explicetely mapped by applications too
sprintf( buffer, "%04X_%04X_%02X%02X%02X ROM",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function );
si->ROM_area = map_physical_memory(
buffer,
(void *) di->rom.phys_address,
di->rom.size,
B_ANY_KERNEL_ADDRESS,
0,
(void **)&(di->rom.rom_ptr));
if( si->ROM_area < 0 ) {
result = si->ROM_area;
goto err2;
}
if( di->pcii.u.h0.base_register_sizes[fb] > di->local_mem_size ) {
// Radeons allocate more address range then really needed ->
@ -88,6 +108,7 @@ status_t Radeon_MapDevice( device_info *di, bool mmio_only )
// this is not a perfect solution; preferably, only
// those areas owned by an application are mapped into
// its address space
// (this hack is needed by BeOS to write something onto screen in KDL)
SHOW_INFO( 1, "physical address of framebuffer: 0x%8lx-0x%8lx",
di->pcii.u.h0.base_registers[fb],
di->pcii.u.h0.base_registers[fb] + di->pcii.u.h0.base_register_sizes[fb] - 1 );
@ -96,29 +117,29 @@ status_t Radeon_MapDevice( device_info *di, bool mmio_only )
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function);
si->fb_area = map_physical_memory(
si->memory[mt_local].area = map_physical_memory(
buffer,
(void *) di->pcii.u.h0.base_registers[fb],
di->pcii.u.h0.base_register_sizes[fb],
B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
B_READ_AREA + B_WRITE_AREA,
(void **)&(si->framebuffer));
(void **)&(si->local_mem));
if (si->fb_area < 0) {
if( si->memory[mt_local].area < 0 ) {
SHOW_FLOW0( 3, "couldn't enable WC for frame buffer" );
si->fb_area = map_physical_memory(
si->memory[mt_local].area = map_physical_memory(
buffer,
(void *) di->pcii.u.h0.base_registers[fb],
di->pcii.u.h0.base_register_sizes[fb],
B_ANY_KERNEL_BLOCK_ADDRESS,
B_READ_AREA + B_WRITE_AREA,
(void **)&(si->framebuffer));
(void **)&(si->local_mem));
}
SHOW_FLOW( 3, "mapped frame buffer @%p", si->framebuffer );
SHOW_FLOW( 3, "mapped frame buffer @%p", si->local_mem );
if (si->fb_area < 0) {
result = si->fb_area;
if( si->memory[mt_local].area < 0 ) {
result = si->memory[mt_local].area;
goto err;
}
@ -128,8 +149,10 @@ status_t Radeon_MapDevice( device_info *di, bool mmio_only )
return B_OK;
err:
delete_area(si->regs_area);
err:
delete_area( si->ROM_area );
err2:
delete_area( si->regs_area );
return result;
}
@ -152,10 +175,13 @@ void Radeon_UnmapDevice(device_info *di)
if( si->regs_area > 0 )
delete_area( si->regs_area );
if( si->fb_area > 0 )
delete_area( si->fb_area );
if( si->ROM_area > 0 )
delete_area( si->ROM_area );
si->regs_area = si->fb_area = 0;
if( si->memory[mt_local].area > 0 )
delete_area( si->memory[mt_local].area );
si->regs_area = si->ROM_area = si->memory[mt_local].area = 0;
}
@ -163,7 +189,7 @@ void Radeon_UnmapDevice(device_info *di)
status_t Radeon_FirstOpen( device_info *di )
{
status_t result;
char buffer[B_OS_NAME_LENGTH];
char buffer[100]; // B_OS_NAME_LENGTH is too short
shared_info *si;
//uint32 /*dma_block, */dma_offset;
@ -189,7 +215,9 @@ status_t Radeon_FirstOpen( device_info *di )
si = di->si;
#ifdef ENABLE_LOGGING
#ifdef LOG_INCLUDE_STARTUP
si->log = log_init( 1000000 );
#endif
#endif
// copy all info into shared info
@ -197,17 +225,28 @@ status_t Radeon_FirstOpen( device_info *di )
si->device_id = di->pcii.device_id;
si->revision = di->pcii.revision;
si->has_crtc2 = di->has_crtc2;
si->asic = di->asic;
si->is_mobility = di->is_mobility;
si->tv_chip = di->tv_chip;
si->ports[0].disp_type = di->disp_type[0];
si->ports[1].disp_type = di->disp_type[1];
si->fp_port = di->fp_info;
// detecting theatre channel in kernel would lead to code duplication,
// so we let the first accelerant take care of it
si->theatre_channel = -1;
/* si->ports[0].disp_type = di->disp_type[0];
si->ports[1].disp_type = di->disp_type[1];*/
si->heads[0].is_crtc2 = false;
si->heads[0].flatpanel_port = 0;
si->heads[1].is_crtc2 = true;
si->heads[1].flatpanel_port = 1;
si->num_heads = di->num_heads;
si->flatpanels[0] = di->fp_info;
si->pll = di->pll;
/* si->ram = di->ram;
strcpy( si->ram_type, di->ram_type );*/
si->local_mem_size = di->local_mem_size;
//si->local_mem_size = di->local_mem_size;
// create virtual card info; don't allow access by apps -
// they'll clone it
sprintf( buffer, "%04X_%04X_%02X%02X%02X virtual card 0",
@ -221,15 +260,13 @@ status_t Radeon_FirstOpen( device_info *di )
B_FULL_LOCK, 0);
if (di->virtual_card_area < 0) {
result = di->virtual_card_area;
goto err5;
goto err7;
}
// currently, we assign fixed ports to this virtual card
di->vc->num_ports = si->has_crtc2 ? 2 : 1;
di->vc->ports[0].is_crtc2 = false;
di->vc->ports[0].physical_port = 0;
di->vc->ports[1].is_crtc2 = true;
di->vc->ports[1].physical_port = 1;
di->vc->num_heads = si->num_heads;
di->vc->heads[0].physical_head = 0;
di->vc->heads[1].physical_head = 1;
di->vc->fb_mem_handle = 0;
di->vc->cursor.mem_handle = 0;
@ -239,30 +276,63 @@ status_t Radeon_FirstOpen( device_info *di )
result = Radeon_MapDevice( di, false );
if (result < 0)
goto err4;
goto err6;
// save dac2_cntl register
// we need to restore that during uninit, else you only get
// garbage on screen on reboot
if( di->has_crtc2 )
// on M6, we need to restore that during uninit, else you only get
// garbage on screen on reboot if both CRTCs are used
if( di->asic == rt_m6 )
di->dac2_cntl = INREG( di->regs, RADEON_DAC_CNTL2 );
result = Radeon_InitDMA( di );
result = Radeon_InitPCIGART( di );
if( result < 0 )
goto err3;
goto err5;
si->memory[mt_local].size = di->local_mem_size;
// currently, we don't support VLI - something is broken there
si->memory[mt_PCI].area = di->pci_gart.buffer.area;
si->memory[mt_PCI].size = di->pci_gart.buffer.size;
// currently, defaultnon-local memory is PCI memory
si->nonlocal_type = mt_PCI;
Radeon_InitMemController( di );
// currently, we don't support VBI - something is broken there
// (it doesn't change a thing apart from crashing)
/* result = Radeon_SetupIRQ( di, buffer );
result = Radeon_SetupIRQ( di, buffer );
if( result < 0 )
goto err2;*/
di->local_memmgr = mem_init( 0, di->local_mem_size, 1024,
goto err4;
// resolution of 2D register is 1K, resolution of CRTC etc. is higher,
// so 1K is the minimum block size;
// (CP cannot use local mem)
di->memmgr[mt_local] = mem_init( 0, di->local_mem_size, 1024,
di->local_mem_size / 1024 );
if( di->local_memmgr == NULL ) {
if( di->memmgr[mt_local] == NULL ) {
result = B_NO_MEMORY;
goto err1;
goto err3;
}
// CP requires 4K alignment, which is the most restrictive I found
di->memmgr[mt_PCI] = mem_init( 0, di->pci_gart.buffer.size, 4096,
di->pci_gart.buffer.size / 4096 );
if( di->memmgr[mt_PCI] == NULL ) {
result = B_NO_MEMORY;
goto err2;
}
// no AGP support
di->memmgr[mt_AGP] = NULL;
// time to init Command Processor
result = Radeon_InitCP( di );
if( result != B_OK )
goto err;
result = Radeon_InitDMA( di );
if( result != B_OK )
goto err0;
//Radeon_Fix_AGP();
@ -273,16 +343,22 @@ status_t Radeon_FirstOpen( device_info *di )
si->nonlocal_vm_start = (uint32)si->framebuffer_pci + dma_offset;*/
return B_OK;
err1:
/*Radeon_CleanupIRQ( di );
err2:*/
Radeon_CleanupDMA( di );
err0:
Radeon_UninitCP( di );
err:
mem_destroy( di->memmgr[mt_PCI] );
err2:
mem_destroy( di->memmgr[mt_local] );
err3:
Radeon_UnmapDevice( di );
Radeon_CleanupIRQ( di );
err4:
delete_area( di->virtual_card_area );
Radeon_CleanupPCIGART( di );
err5:
Radeon_UnmapDevice( di );
err6:
delete_area( di->virtual_card_area );
err7:
delete_area( di->shared_area );
err8:
return result;
@ -294,17 +370,30 @@ err8:
// during tests)
void Radeon_LastClose( device_info *di )
{
if( di->has_crtc2 )
OUTREG( di->regs, RADEON_DAC_CNTL2, di->dac2_cntl );
Radeon_UninitCP( di );
mem_destroy( di->local_memmgr );
// M6 fix - unfortunately, the device is never closed by app_server,
// not even before reboot
if( di->asic == rt_m6 )
OUTREG( di->regs, RADEON_DAC_CNTL2, di->dac2_cntl );
mem_destroy( di->memmgr[mt_local] );
// Radeon_CleanupIRQ( di );
Radeon_CleanupDMA( di );
if( di->memmgr[mt_PCI] )
mem_destroy( di->memmgr[mt_PCI] );
if( di->memmgr[mt_AGP] )
mem_destroy( di->memmgr[mt_AGP] );
Radeon_CleanupIRQ( di );
Radeon_CleanupPCIGART( di );
Radeon_UnmapDevice(di);
#ifdef ENABLE_LOGGING
#ifdef LOG_INCLUDE_STARTUP
log_exit( di->si->log );
#endif
#endif
delete_area( di->virtual_card_area );

View File

@ -11,70 +11,132 @@
#include "radeon_driver.h"
#include <stdio.h>
#include <mmio.h>
#include <rbbm_regs.h>
#include "mmio.h"
#include "rbbm_regs.h"
// disable all interrupts
static void Radeon_DisableIRQ( device_info *di )
static void
Radeon_DisableIRQ( device_info *di )
{
OUTREG( di->regs, RADEON_GEN_INT_CNTL, 0 );
}
static uint32 thread_interrupt_work( vuint8 *regs, device_info *di, uint32 int_status )
// interrupt worker routine
// handles standard interrupts, i.e. VBI and DMA
static uint32
Radeon_ThreadInterruptWork( vuint8 *regs, device_info *di, uint32 int_status )
{
shared_info *si = di->si;
uint32 handled = B_HANDLED_INTERRUPT;
if( (int_status & RADEON_CRTC_VBLANK_STAT) != 0 &&
si->ports[0].vblank >= 0 )
si->heads[0].vblank >= 0 )
{
int32 blocked;
++di->vbi_count[0];
if( (get_sem_count( si->ports[0].vblank, &blocked ) == B_OK) && (blocked < 0) ) {
//SHOW_FLOW( 3, "Signalled VBI 0 (%ldx)", -blocked );
release_sem_etc( si->ports[0].vblank, -blocked, B_DO_NOT_RESCHEDULE );
if( (get_sem_count( si->heads[0].vblank, &blocked ) == B_OK) && (blocked < 0) ) {
release_sem_etc( si->heads[0].vblank, -blocked, B_DO_NOT_RESCHEDULE );
handled = B_INVOKE_SCHEDULER;
}
}
if( (int_status & RADEON_CRTC2_VBLANK_STAT) != 0 &&
si->ports[1].vblank >= 0 )
si->heads[1].vblank >= 0 )
{
int32 blocked;
++di->vbi_count[1];
if( (get_sem_count( si->ports[1].vblank, &blocked ) == B_OK) && (blocked < 0) ) {
//SHOW_FLOW( 3, "Signalled VBI 1 (%ldx)", -blocked );
release_sem_etc( si->ports[1].vblank, -blocked, B_DO_NOT_RESCHEDULE );
if( (get_sem_count( si->heads[1].vblank, &blocked ) == B_OK) && (blocked < 0) ) {
release_sem_etc( si->heads[1].vblank, -blocked, B_DO_NOT_RESCHEDULE );
handled = B_INVOKE_SCHEDULER;
}
}
if( (int_status & RADEON_VIDDMA_STAT ) != 0 ) {
release_sem_etc( di->dma_sem, 1, B_DO_NOT_RESCHEDULE );
handled = B_INVOKE_SCHEDULER;
}
return handled;
}
// Capture interrupt handler
static int32
Radeon_HandleCaptureInterrupt( vuint8 *regs, device_info *di, uint32 cap_status )
{
int32 blocked;
uint32 handled = B_HANDLED_INTERRUPT;
cpu_status prev_irq_state = disable_interrupts();
acquire_spinlock( &di->cap_spinlock );
++di->cap_counter;
di->cap_int_status = cap_status;
di->cap_timestamp = system_time();
release_spinlock( &di->cap_spinlock );
restore_interrupts( prev_irq_state );
// don't release if semaphore count is positive, i.e. notifications are piling up
if( (get_sem_count( di->cap_sem, &blocked ) == B_OK) && (blocked <= 0) ) {
release_sem_etc( di->cap_sem, 1, B_DO_NOT_RESCHEDULE );
handled = B_INVOKE_SCHEDULER;
}
// acknowledge IRQ
OUTREG( regs, RADEON_CAP_INT_STATUS, cap_status );
return handled;
}
// Main interrupt handler
static int32
Radeon_Interrupt(void *data)
{
int32 handled = B_UNHANDLED_INTERRUPT;
device_info *di = (device_info *)data;
vuint8 *regs = di->regs;
int32 int_status;
int32 full_int_status, int_status;
int_status = INREG( regs, RADEON_GEN_INT_STATUS );
// read possible IRQ reasons, ignoring any masked IRQs
full_int_status = INREG( regs, RADEON_GEN_INT_STATUS );
int_status = full_int_status & INREG( regs, RADEON_GEN_INT_CNTL );
if( int_status != 0 ) {
++di->interrupt_count;
handled = thread_interrupt_work( regs, di, int_status );
handled = Radeon_ThreadInterruptWork( regs, di, int_status );
// acknowledge IRQ
OUTREG( regs, RADEON_GEN_INT_STATUS, int_status );
}
// capture interrupt have no mask in GEN_INT_CNTL register;
// probably, ATI wanted to make capture interrupt control independant of main control
if( (full_int_status & RADEON_CAP0_INT_ACTIVE) != 0 ) {
int32 cap_status;
// same as before: only regard enabled IRQ reasons
cap_status = INREG( regs, RADEON_CAP_INT_STATUS );
cap_status &= INREG( regs, RADEON_CAP_INT_CNTL );
if( cap_status != 0 ) {
int32 cap_handled;
cap_handled = Radeon_HandleCaptureInterrupt( regs, di, cap_status );
if( cap_handled == B_INVOKE_SCHEDULER || handled == B_INVOKE_SCHEDULER )
handled = B_INVOKE_SCHEDULER;
else if( cap_handled == B_HANDLED_INTERRUPT )
handled = B_HANDLED_INTERRUPT;
}
}
return handled;
}
@ -102,9 +164,9 @@ static int32 timer_interrupt_func( timer *te )
when -= si->blank_period - 4;
}
/* do the things we do when we notice a vertical retrace */
result = thread_interrupt_work( regs, di,
result = Radeon_ThreadInterruptWork( regs, di,
RADEON_CRTC_VBLANK_STAT |
(di->has_crtc2 ? RADEON_CRTC_VBLANK_STAT : 0 ));
(di->num_heads > 1 ? RADEON_CRTC2_VBLANK_STAT : 0 ));
}
/* pick the "other" timer */
@ -121,39 +183,70 @@ static int32 timer_interrupt_func( timer *te )
return result;
}
status_t Radeon_SetupIRQ( device_info *di, char *buffer )
// setup IRQ handlers.
// includes an VBI emulator via a timer (according to sample code),
// though this makes sense for one CRTC only
status_t
Radeon_SetupIRQ( device_info *di, char *buffer )
{
shared_info *si = di->si;
status_t result;
thread_id thid;
thread_info thinfo;
sprintf( buffer, "%04X_%04X_%02X%02X%02X VBI 0",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function );
si->ports[0].vblank = create_sem( 0, buffer );
if( si->ports[0].vblank < 0 ) {
result = si->ports[0].vblank;
goto err1;
}
sprintf( buffer, "%04X_%04X_%02X%02X%02X VBI 1",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function );
si->ports[1].vblank = create_sem( 0, buffer );
if( si->ports[1].vblank < 0 ) {
result = si->ports[1].vblank;
goto err2;
si->heads[0].vblank = create_sem( 0, buffer );
if( si->heads[0].vblank < 0 ) {
result = si->heads[0].vblank;
goto err1;
}
si->heads[1].vblank = 0;
if( di->num_heads > 1 ) {
sprintf( buffer, "%04X_%04X_%02X%02X%02X VBI 2",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function );
si->heads[1].vblank = create_sem( 0, buffer );
if( si->heads[1].vblank < 0 ) {
result = si->heads[1].vblank;
goto err2;
}
}
sprintf( buffer, "%04X_%04X_%02X%02X%02X Cap I",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function );
di->cap_sem = create_sem( 0, buffer );
if( di->cap_sem < 0 ) {
result = di->cap_sem;
goto err3;
}
di->cap_spinlock = 0;
sprintf( buffer, "%04X_%04X_%02X%02X%02X DMA I",
di->pcii.vendor_id, di->pcii.device_id,
di->pcii.bus, di->pcii.device, di->pcii.function );
di->dma_sem = create_sem( 0, buffer );
if( di->dma_sem < 0 ) {
result = di->dma_sem;
goto err4;
}
/* change the owner of the semaphores to the opener's team */
/* this is required because apps can't aquire kernel semaphores */
thid = find_thread(NULL);
get_thread_info(thid, &thinfo);
set_sem_owner(si->ports[0].vblank, thinfo.team);
set_sem_owner(si->ports[1].vblank, thinfo.team);
get_thread_info(thid, &thinfo);
set_sem_owner(si->heads[0].vblank, thinfo.team);
if( di->num_heads > 1 )
set_sem_owner(si->heads[1].vblank, thinfo.team);
//set_sem_owner(di->cap_sem, thinfo.team);
/* disable and clear any pending interrupts */
/* disable all interrupts */
Radeon_DisableIRQ( di );
/* if we're faking interrupts */
@ -172,29 +265,36 @@ status_t Radeon_SetupIRQ( device_info *di, char *buffer )
result = add_timer((timer *)(di->current_timer), timer_interrupt_func,
si->refresh_period, B_ONE_SHOT_RELATIVE_TIMER);
if( result != B_OK )
goto err3;
goto err5;
} else {
/* otherwise install our interrupt handler */
result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line,
Radeon_Interrupt, (void *)di, 0);
if( result != B_OK )
goto err3;
goto err5;
SHOW_INFO( 3, "installed IRQ @ %d", di->pcii.u.h0.interrupt_line );
}
return B_OK;
err5:
delete_sem( di->dma_sem );
err4:
delete_sem( di->cap_sem );
err3:
delete_sem( si->ports[1].vblank );
if( di->num_heads > 1 )
delete_sem( si->heads[1].vblank );
err2:
delete_sem( si->ports[0].vblank );
delete_sem( si->heads[0].vblank );
err1:
return result;
}
void Radeon_CleanupIRQ( device_info *di )
// clean-up interrupt handling
void
Radeon_CleanupIRQ( device_info *di )
{
shared_info *si = di->si;
@ -212,9 +312,14 @@ void Radeon_CleanupIRQ( device_info *di )
/* remove interrupt handler */
remove_io_interrupt_handler(di->pcii.u.h0.interrupt_line, Radeon_Interrupt, di);
}
delete_sem( si->ports[1].vblank );
delete_sem( si->ports[0].vblank );
si->ports[1].vblank = si->ports[0].vblank = 0;
delete_sem( si->heads[0].vblank );
if( di->num_heads > 1 )
delete_sem( si->heads[1].vblank );
delete_sem( di->cap_sem );
delete_sem( di->dma_sem );
di->cap_sem = si->heads[1].vblank = si->heads[0].vblank = 0;
}

View File

@ -0,0 +1,193 @@
/*
Copyright (c) 2002, Thomas Kurschel
Part of Radeon kernel driver
Memory controller setup.
The memory controller of the Radeon provides a universal mapping
from addresses generated by the different DMA units within the
graphics chip to addresses in local/PCI/AGP memory. Here, we
set this mapping up.
Further we initialize some bus controller registers here (where bus
means non-local memory interface).
*/
#include "radeon_driver.h"
#include "buscntrl_regs.h"
#include "mmio.h"
#include "memcntrl_regs.h"
// get last RAM address + 1, i.e. first unused physical address
static uint32 getTopOfRam()
{
system_info info;
// there is no function to really get this info;
// as a hack, we ask for number of physical RAM pages and hope
// they are contigous, starting at address 0
get_system_info( &info );
return info.max_pages * 4096;
}
// graphics card addresses correspond to physical CPU addresses as much as possible
static void Radeon_SetupMCAddresses_Direct( device_info *di )
{
shared_info *si = di->si;
// set address range of video memory;
// use the same addresses the CPU sees
si->memory[mt_local].virtual_addr_start = (uint32)si->framebuffer_pci;
si->memory[mt_local].virtual_size = di->local_mem_size;
// PCI GART has no corresponding CPU address space, so we must find an unused
// one; we assume that the addresses directly after physical RAM are
// not in use as the BIOS should have allocated address for PCI devices
// starting with highest address possible.
// no problem in terms of alignment: it must be a multiple 4K only
si->memory[mt_PCI].virtual_addr_start = (getTopOfRam() + 4095) & ~4095;
si->memory[mt_PCI].virtual_size = ATI_MAX_PCIGART_PAGES * ATI_PCIGART_PAGE_SIZE;
// similar problem with AGP: though there _is_ a corresponding CPU address space,
// we don't know it (this would require finding the AGP bridge and
// getting info from there, which would be a dangerous hack);
// solution is to locate AGP aperture directly after PCI GART;
// we define a 4 MB aperture to meet any possible alignment restrictions
si->memory[mt_AGP].virtual_addr_start =
(si->memory[mt_PCI].virtual_addr_start + si->memory[mt_PCI].virtual_size
+ 0x3fffff) & ~0x3fffff;
si->memory[mt_AGP].virtual_size = 0x400000;
}
#if 0
// graphics card addresses are mapped in a way to restrict direct main memory access
static void Radeon_SetupMCAddresses_Safe( device_info *di )
{
shared_info *si = di->si;
// any address not covered by frame buffer, PCI GART or AGP aperture
// leads to a direct memory access
// -> this is dangerous, so we make sure entire address space is mapped
// locate PCI GART at top of address space
// warning about size: there are quite strong alignment restrictions,
// so we better obey!
si->memory[mt_PCI].virtual_size = ATI_MAX_PCIGART_PAGES * ATI_PCIGART_PAGE_SIZE;
si->memory[mt_PCI].virtual_addr_start = 0 - si->memory[mt_PCI].virtual_size;
// let AGP range overlap with frame buffer to hide it;
// according to spec, frame buffer should win but we better
// choose an unused-area to avoid trouble
// (specs don't talk about overlapping area, let's hope
// the memory controller won't choke if we ever access it)
si->memory[mt_AGP].virtual_size = 0x400000;
si->memory[mt_AGP].virtual_addr_start =
si->memory[mt_PCI].virtual_addr_start -
si->memory[mt_AGP].virtual_size;
// set address range of video memory
// let it cover all remaining addresses;
// addresses are wrapped
si->memory[mt_local].virtual_addr_start = 0;
si->memory[mt_local].virtual_size =
si->memory[mt_AGP].virtual_addr_start -
si->memory[mt_local].virtual_addr_start;
}
#endif
// graphics cards addresses are mapped IGP compliantly
static void Radeon_SetupMCAddresses_IGP( device_info *di )
{
shared_info *si = di->si;
uint32 tom;
// the frame buffer memory address range is read from TOM register
// it located at end of physical RAM (at least it seems so)
tom = INREG( di->regs, RADEON_GC_NB_TOM );
si->memory[mt_local].virtual_addr_start = (tom & 0xffff) << 16;
si->memory[mt_local].virtual_size =
(((tom >> 16) + 1) << 16) -
si->memory[mt_local].virtual_addr_start;
// after the frame buffer, physical memory should end and unused
// physical addresses start - good location to put the PCI GART to
si->memory[mt_PCI].virtual_addr_start = ((((tom >> 16) + 1) << 16) + 4095) & ~4095;
si->memory[mt_PCI].virtual_size = ATI_MAX_PCIGART_PAGES * ATI_PCIGART_PAGE_SIZE;
// locate AGP aperture after PCI GART
si->memory[mt_AGP].virtual_addr_start =
(si->memory[mt_PCI].virtual_addr_start +
si->memory[mt_PCI].virtual_size + 0x3fffff) & ~0x3fffff;
si->memory[mt_AGP].virtual_size = 0x400000;
}
void Radeon_InitMemController( device_info *di )
{
vuint8 *regs = di->regs;
shared_info *si = di->si;
if( di->is_igp )
Radeon_SetupMCAddresses_IGP( di );
else
Radeon_SetupMCAddresses_Direct/*Radeon_SetupMCAddresses_Safe*/( di );
SHOW_INFO0( 3, "Graphics card address mapping:" );
SHOW_INFO( 3, " local memory 0x%lx@0x%lx",
si->memory[mt_local].virtual_size, si->memory[mt_local].virtual_addr_start );
SHOW_INFO( 3, " PCI GART 0x%lx@0x%lx",
si->memory[mt_PCI].virtual_size, si->memory[mt_PCI].virtual_addr_start );
SHOW_INFO( 3, " disabled AGP GART 0x%lx@0x%lx",
si->memory[mt_AGP].virtual_size, si->memory[mt_AGP].virtual_addr_start );
//si->nonlocal_mem = di->DMABuffer.ptr;
// set PCI GART page-table base address
OUTREG( regs, RADEON_AIC_PT_BASE, di->pci_gart.GATT.phys );
// set address range for PCI address translation
// we must restrict range to the actually used GART size here!
OUTREG( regs, RADEON_AIC_LO_ADDR, si->memory[mt_PCI].virtual_addr_start );
OUTREG( regs, RADEON_AIC_HI_ADDR, si->memory[mt_PCI].virtual_addr_start +
si->memory[mt_PCI].virtual_size/*di->pci_gart.buffer.size*/ - 1 );
// set AGP address range
OUTREG( regs, RADEON_MC_AGP_LOCATION,
(si->memory[mt_AGP].virtual_addr_start >> 16) |
((si->memory[mt_AGP].virtual_addr_start + si->memory[mt_AGP].virtual_size - 1) & 0xffff0000 ));
// set address range of video memory
// (lower word = begin >> 16
// upper word = end >> 16)
OUTREG( regs, RADEON_MC_FB_LOCATION,
((si->memory[mt_local].virtual_addr_start + si->memory[mt_local].virtual_size - 1) & 0xffff0000) |
(si->memory[mt_local].virtual_addr_start >> 16) );
// base address of CRTC and others must be same as frame buffer address
// (we could specify any address too, but local memory is of course first choice)
OUTREG( regs, RADEON_DISPLAY_BASE_ADDRESS, si->memory[mt_local].virtual_addr_start );
OUTREG( regs, RADEON_CRTC2_DISPLAY_BASE_ADDRESS, si->memory[mt_local].virtual_addr_start );
OUTREG( regs, RADEON_OV0_BASE_ADDRESS, si->memory[mt_local].virtual_addr_start );
// disable AGP
OUTREG( regs, RADEON_AGP_COMMAND, 0 );
// Turn on PCI GART
OUTREGP( regs, RADEON_AIC_CNTL, RADEON_PCIGART_TRANSLATE_EN,
~RADEON_PCIGART_TRANSLATE_EN );
// fix some bus controller setting
// I reckon this takes care of discarding data unnecessarily read
// during a burst; let's hope this will fix the nasty CP crashing problem
OUTREGP( regs, RADEON_BUS_CNTL, RADEON_BUS_RD_DISCARD_EN, ~RADEON_BUS_RD_DISCARD_EN );
// SHOW_FLOW0( 3, "done" );
}

View File

@ -1,255 +0,0 @@
/*
Copyright (c) 2002, Thomas Kurschel
Part of Radeon kernel driver
Memory manager used for graphics mem
It has the following features
- doesn't access memory to be managed
- memory block's owner is identified by tag,
tag is verified during free, and all memory
belonging to one tag can be freed at once
- multi-threading save
*/
#include "memmgr.h"
#include <stdlib.h>
#include "radeon_driver.h"
// init manager
// start - start of address space
// len - len of address space
// block_size - granularity
// heap_entries - maximum number of blocks
mem_info *mem_init( uint32 start, uint32 len, uint32 block_size, uint32 heap_entries )
{
mem_block *first;
mem_info *mem;
uint i;
SHOW_FLOW( 2, "start=%lx, len=%lx, block_size=%lx, heap_entries=%ld",
start, len, block_size, heap_entries );
mem = malloc( sizeof( *mem ));
if( mem == NULL )
goto err;
mem->block_size = block_size;
mem->heap_entries = heap_entries;
mem->lock = create_sem( 1, "mem_lock" );
if( mem->lock < 0 )
goto err2;
mem->heap = malloc( heap_entries * sizeof( mem_block ));
if( mem->heap == NULL )
goto err3;
for( i = 1; i < heap_entries; ++i )
mem->heap[i].next = &mem->heap[i+1];
mem->heap[heap_entries - 1].next = NULL;
mem->unused = &mem->heap[1];
first = &mem->heap[0];
mem->first = first;
first->base = start;
first->size = len;
first->prev = first->next = NULL;
first->alloced = false;
return mem;
err3:
delete_sem( mem->lock );
err2:
free( mem );
err:
return NULL;
}
// destroy heap
void mem_destroy( mem_info *mem )
{
SHOW_FLOW0( 2, "" );
free( mem->heap );
delete_sem( mem->lock );
free( mem );
}
// allocate memory block
// in:
// mem - heap handle
// size - size in bytes
// tag - owner tag
// out:
// block - block id
// offset - start address of block
status_t mem_alloc( mem_info *mem, uint32 size, void *tag, uint32 *block, uint32 *offset )
{
mem_block *cur, *new_entry;
SHOW_FLOW( 2, "size=%ld, tag=%p", size, tag );
acquire_sem( mem->lock );
// we assume block_size is power of two
size = (size + mem->block_size - 1) & ~(mem->block_size - 1);
// simple first fit
for( cur = mem->first; cur; cur = cur->next ) {
if( !cur->alloced && cur->size >= size )
break;
}
if( cur == NULL ) {
SHOW_FLOW0( 2, "out of memory" );
goto err;
}
if( size != cur->size ) {
new_entry = mem->unused;
if( new_entry == NULL ) {
SHOW_FLOW0( 2, "out of blocks" );
goto err;
}
mem->unused = new_entry->next;
new_entry->next = cur->next;
new_entry->prev = cur;
new_entry->alloced = false;
new_entry->base = cur->base + size;
new_entry->size = cur->size - size;
if( cur->next )
cur->next->prev = new_entry;
cur->next = new_entry;
cur->size = size;
}
cur->alloced = true;
cur->tag = tag;
*block = cur - mem->heap + 1;
*offset = cur->base;
release_sem( mem->lock );
SHOW_FLOW( 2, "block_id=%ld, offset=%lx", *block, *offset );
return B_OK;
err:
release_sem( mem->lock );
return B_NO_MEMORY;
}
// merge "block" with successor
static void merge( mem_info *mem, mem_block *block )
{
mem_block *next;
next = block->next;
block->size += next->size;
if( next->next )
next->next->prev = block;
block->next = next->next;
next->next = mem->unused;
mem->unused = next;
}
// internal: free memory block including merge
static mem_block *freeblock( mem_info *mem, mem_block *block )
{
mem_block *prev, *next;
block->alloced = false;
prev = block->prev;
if( prev && !prev->alloced ) {
block = prev;
merge( mem, prev );
}
next = block->next;
if( next && !next->alloced )
merge( mem, block );
return block;
}
// free memory
// mem - heap handle
// block_id - block id
// tag - owner tag (must match tag passed to mem_alloc)
status_t mem_free( mem_info *mem, uint32 block_id, void *tag )
{
mem_block *block;
SHOW_FLOW( 2, "block_id=%ld, tag=%p", block_id, tag );
acquire_sem( mem->lock );
--block_id;
if( block_id >= mem->heap_entries ) {
SHOW_FLOW0( 2, "invalid id" );
goto err;
}
block = &mem->heap[block_id];
if( !block->alloced || block->tag != tag ) {
SHOW_FLOW0( 2, "not owner" );
goto err;
}
freeblock( mem, block );
release_sem( mem->lock );
SHOW_FLOW0( 2, "success" );
return B_OK;
err:
release_sem( mem->lock );
return B_BAD_VALUE;
}
// free all memory belonging to owner "tag"
void mem_freetag( mem_info *mem, void *tag )
{
mem_block *cur;
SHOW_FLOW( 2, "tag=%p", tag );
acquire_sem( mem->lock );
for( cur = mem->first; cur; cur = cur->next ) {
if( cur->alloced && cur->tag == tag )
cur = freeblock( mem, cur );
}
release_sem( mem->lock );
SHOW_FLOW0( 2, "done" );
}

View File

@ -1,43 +0,0 @@
/*
Copyright (c) 2002, Thomas Kurschel
Part of Radeon kernel driver
Memory manager used for graphics mem
*/
#ifndef _MEMMGR_H
#define _MEMMGR_H
#include <OS.h>
// allocated memory block
typedef struct mem_block {
struct mem_block *prev, *next;
uint32 base;
uint32 size;
void *tag;
bool alloced;
} mem_block;
// memory heap
typedef struct mem_info {
mem_block *first;
uint32 block_size;
sem_id lock;
mem_block *heap;
mem_block *unused;
uint32 heap_entries;
} mem_info;
mem_info *mem_init( uint32 start, uint32 len, uint32 block_size, uint32 heap_entries );
void mem_destroy( mem_info *mem );
status_t mem_alloc( mem_info *mem, uint32 size, void *tag, uint32 *block, uint32 *offset );
status_t mem_free( mem_info *mem, uint32 block_id, void *tag );
void mem_freetag( mem_info *mem, void *tag );
#endif

View File

@ -0,0 +1,66 @@
/*
Copyright (c) 2002/03, Thomas Kurschel
Part of Radeon driver and accelerant
Basic access of PLL registers
*/
#include "radeon_interface.h"
#include "pll_access.h"
#include "pll_regs.h"
#include "utils.h"
// read value "val" from PLL-register "addr"
uint32 Radeon_INPLL( vuint8 *regs, radeon_type asic, int addr )
{
uint32 res;
OUTREG8( regs, RADEON_CLOCK_CNTL_INDEX, addr & 0x3f );
res = INREG( regs, RADEON_CLOCK_CNTL_DATA );
R300_PLLFix( regs, asic );
return res;
}
// write value "val" to PLL-register "addr"
void Radeon_OUTPLL( vuint8 *regs, radeon_type asic, uint8 addr, uint32 val )
{
(void)asic;
OUTREG8( regs, RADEON_CLOCK_CNTL_INDEX, ((addr & 0x3f ) |
RADEON_PLL_WR_EN));
OUTREG( regs, RADEON_CLOCK_CNTL_DATA, val );
// TBD: on XFree, there is no call of R300_PLLFix here,
// though it should as we've accessed CLOCK_CNTL_INDEX
//R300_PLLFix( ai );
}
// write "val" to PLL-register "addr" keeping bits "mask"
void Radeon_OUTPLLP( vuint8 *regs, radeon_type asic, uint8 addr,
uint32 val, uint32 mask )
{
uint32 tmp = Radeon_INPLL( regs, asic, addr );
tmp &= mask;
tmp |= val;
Radeon_OUTPLL( regs, asic, addr, tmp );
}
// r300: to be called after each CLOCK_CNTL_INDEX access
// (hardware bug fix suggested by XFree86)
void R300_PLLFix( vuint8 *regs, radeon_type asic )
{
uint32 save, tmp;
if( asic != rt_r300 )
return;
save = INREG( regs, RADEON_CLOCK_CNTL_INDEX );
tmp = save & ~(0x3f | RADEON_PLL_WR_EN);
OUTREG( regs, RADEON_CLOCK_CNTL_INDEX, tmp );
tmp = INREG( regs, RADEON_CLOCK_CNTL_DATA );
OUTREG( regs, RADEON_CLOCK_CNTL_INDEX, save );
}

View File

@ -10,7 +10,7 @@
#ifndef _RADEON_DRIVER_H
#define _RADEON_DRIVER_H
#include <radeon_interface.h>
#include "radeon_interface.h"
#include "memmgr.h"
#include <KernelExport.h>
@ -26,27 +26,39 @@ extern int debug_level_error;
#define DEBUG_WAIT_ON_ERROR 1000000*/
#define DEBUG_MSG_PREFIX "Radeon - "
#include <debug_ext.h>
#include "debug_ext.h"
#ifdef ENABLE_LOGGING
#include "log_coll.h"
#endif
#define MAX_DEVICES 8
// size of PCI GART;
// the only user is the command processor, which needs 1 MB,
// so make sure that GART is large enough
#define PCI_GART_SIZE 1024*1024
// DMA buffer
typedef struct DMA_buffer {
area_id buffer_area;
size_t size;
void *ptr;
area_id GART_area;
uint32 *GART_ptr;
uint32 GART_phys;
area_id unaligned_area;
} DMA_buffer;
// size of CP ring buffer in dwords
#define CP_RING_SIZE 2048
// GART info (either PCI or AGP)
typedef struct {
// data accessed via GART
struct {
area_id area; // area of data
size_t size; // size of buffer
void *ptr; // CPU pointer to data
area_id unaligned_area; // unaligned address (see PCI_GART.c)
} buffer;
// GATT info (address translation table)
struct {
area_id area; // area containing GATT
uint32 *ptr; // CPU pointer to GATT
uint32 phys; // physical address of GATT
} GATT;
} GART_info;
// info about graphics RAM
typedef struct {
@ -61,9 +73,15 @@ typedef struct {
int Rloop;
} ram_info;
// ROM information
typedef struct {
area_id bios_area;
area_id bios_area; // only mapped during detection
uint32 phys_address; // physical address of BIOS
uint32 size; // size in bytes
// the following is only useful if ROM is mapped during detection,
// but the difference if the offset of hw info
uint8 *bios_ptr; // begin of entire BIOS
uint8 *rom_ptr; // begin of ROM containing hw info
} rom_info;
@ -87,21 +105,29 @@ typedef struct device_info {
virtual_card *vc;
vuint8 *regs;
bool has_crtc2;
radeon_type asic;
display_type_e disp_type[2];
uint8 num_heads;
tv_chip_type tv_chip;
bool is_mobility;
bool is_igp;
bool has_vip;
//display_type_e disp_type[2];
fp_info fp_info;
pll_info pll;
general_pll_info pll;
ram_info ram;
char ram_type[32]; // human-readable name of ram type
uint32 local_mem_size;
rom_info rom;
DMA_buffer DMABuffer;
GART_info pci_gart; // PCI GART
GART_info agp_gart; // AGP GART (unsupported)
memory_type_e nonlocal_map; // default type of non-local memory;
mem_info *local_memmgr;
mem_info *memmgr[mt_last+1]; // memory managers;
// if there is no AGP; the entries for non_local
// and PCI are the same
// VBI data
uint32 interrupt_count;
@ -112,10 +138,24 @@ typedef struct device_info {
timer_info ti_b;
timer_info *current_timer; /* the timer buffer that's currently in use */
// DMA GUI engine
sem_id dma_sem;
uint32 dma_desc_max_num;
uint32 dma_desc_handle;
uint32 dma_desc_offset;
// capture engine
spinlock cap_spinlock; // synchronization for following capture data
sem_id cap_sem; // semaphore released on capture interrupt
uint32 cap_int_status; // content of CAP_INT_STATUS during lost capture irq
uint32 cap_counter; // counter of capture interrupts
bigtime_t cap_timestamp; // timestamp of last capture interrupt
uint32 dac2_cntl; // original dac2_cntl register content
pci_info pcii;
char name[MAX_RADEON_DEVICE_NAME_LENGTH];
char name[MAX_RADEON_DEVICE_NAME_LENGTH];
char video_name[MAX_RADEON_DEVICE_NAME_LENGTH];
} device_info;
@ -123,7 +163,8 @@ typedef struct device_info {
typedef struct {
uint32 count;
benaphore kernel;
char *device_names[MAX_DEVICES+1];
// every device is exported as a graphics and a video card
char *device_names[2*MAX_DEVICES+1];
device_info di[MAX_DEVICES];
} radeon_devices;
@ -150,9 +191,9 @@ void Radeon_UnmapBIOS( rom_info *ri );
status_t Radeon_ReadBIOSData( device_info *di );
// dma.c
void Radeon_CleanupDMA( device_info *di );
status_t Radeon_InitDMA( device_info *di );
// PCI_GART.c
status_t Radeon_InitPCIGART( device_info *di );
void Radeon_CleanupPCIGART( device_info *di );
// irq.c
@ -163,4 +204,29 @@ void Radeon_CleanupIRQ( device_info *di );
// agp.c
void Radeon_Fix_AGP();
// mem_controller.c
void Radeon_InitMemController( device_info *di );
// CP_setup.c
void Radeon_WaitForIdle( device_info *di, bool acquire_lock, bool keep_lock );
void Radeon_WaitForFifo( device_info *di, int entries );
void Radeon_ResetEngine( device_info *di );
status_t Radeon_InitCP( device_info *di );
void Radeon_UninitCP( device_info *di );
// vip.c
bool Radeon_VIPRead( device_info *di, uint channel, uint address, uint32 *data );
bool Radeon_VIPWrite( device_info *di, uint8 channel, uint address, uint32 data );
int Radeon_FindVIPDevice( device_info *di, uint32 device_id );
// dma.c
status_t Radeon_InitDMA( device_info *di );
status_t Radeon_DMACopy(
device_info *di, uint32 src, char *target, size_t size,
bool lock_mem, bool contiguous );
#endif

View File

@ -0,0 +1,26 @@
/*
Copyright (c) 2002, Thomas Kurschel
Part of Radeon driver
some utility functions
*/
#include "OS.h"
#include "utils.h"
// get ceil( log2( size ))
int log2( uint32 x )
{
int res;
uint32 tmp;
for( res = 0, tmp = x ; tmp > 1 ; ++res )
tmp >>= 1;
if( (x & ((1 << res) - 1)) != 0 )
++res;
return res;
}

View File

@ -0,0 +1,241 @@
/*
Copyright (c) 2002-04, Thomas Kurschel
Part of Radeon accelerant
Access to VIP
This code must be in kernel because we need for FIFO to become empty
during VIP access (which in turn requires locking the card, and locking
is a dangerous thing in user mode as the app can suddenly die, taking
the lock with it)
*/
#include "radeon_driver.h"
#include "mmio.h"
#include "vip_regs.h"
#include "bios_regs.h"
#include "theatre_regs.h"
// moved to bottom to avoid inlining
static bool Radeon_VIPWaitForIdle( device_info *di );
// read data from VIP
// CP lock must be hold
static bool do_VIPRead( device_info *di, uint channel, uint address, uint32 *data )
{
vuint8 *regs = di->regs;
Radeon_WaitForFifo( di, 2 );
// the 0x2000 is the nameless "register-read" flag
OUTREG( regs, RADEON_VIPH_REG_ADDR, (channel << 14) | address | 0x2000 );
if( !Radeon_VIPWaitForIdle( di ))
return false;
// enable VIP register cycle reads
Radeon_WaitForFifo( di, 2 );
OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT, 0,
~RADEON_VIPH_TIMEOUT_STAT_AK_MASK & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS );
//Radeon_WaitForIdle( di, false, false );
// this read starts a register cycle; the returned value has no meaning
INREG( regs, RADEON_VIPH_REG_DATA );
if( !Radeon_VIPWaitForIdle( di ))
return false;
//Radeon_WaitForIdle( di, false, false );
// register cycle is done, so disable any further cycle
Radeon_WaitForFifo( di, 2 );
OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT, RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS,
~RADEON_VIPH_TIMEOUT_STAT_AK_MASK & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS );
//Radeon_WaitForIdle( di, false, false );
// get the data
*data = INREG( regs, RADEON_VIPH_REG_DATA );
//SHOW_FLOW( 4, "channel=%d, address=%x, data=%lx", channel, address, *data );
if( !Radeon_VIPWaitForIdle( di ))
return false;
// disable register cycle again (according to sample code)
// IMHO, this is not necessary as it has been done before
Radeon_WaitForFifo( di, 2 );
OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT, RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS,
~RADEON_VIPH_TIMEOUT_STAT_AK_MASK & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS );
return true;
}
// public function: read data from VIP
bool Radeon_VIPRead( device_info *di, uint channel, uint address, uint32 *data )
{
bool res;
ACQUIRE_BEN( di->si->cp.lock );
res = do_VIPRead( di, channel, address, data );
RELEASE_BEN( di->si->cp.lock );
return res;
}
// write data to VIP
// not must be hold
static bool do_VIPWrite( device_info *di, uint8 channel, uint address, uint32 data )
{
vuint8 *regs = di->regs;
bool res;
Radeon_WaitForFifo( di, 2 );
OUTREG( regs, RADEON_VIPH_REG_ADDR, (channel << 14) | (address & ~0x2000) );
if( !Radeon_VIPWaitForIdle( di ))
return false;
//SHOW_FLOW( 4, "channel=%d, address=%x, data=%lx", channel, address, data );
Radeon_WaitForFifo( di, 2 );
OUTREG( regs, RADEON_VIPH_REG_DATA, data );
res = Radeon_VIPWaitForIdle( di );
return res;
}
// public function: write data to VIP
bool Radeon_VIPWrite( device_info *di, uint8 channel, uint address, uint32 data )
{
bool res;
ACQUIRE_BEN( di->si->cp.lock );
res = do_VIPWrite( di, channel, address, data );
RELEASE_BEN( di->si->cp.lock );
return res;
}
// reset VIP
static void VIPReset( device_info *di )
{
vuint8 *regs = di->regs;
ACQUIRE_BEN( di->si->cp.lock );
Radeon_WaitForFifo( di, 5 );
OUTREG( regs, RADEON_VIPH_CONTROL,
4 |
(15 << RADEON_VIPH_CONTROL_VIPH_MAX_WAIT_SHIFT) |
RADEON_VIPH_CONTROL_VIPH_DMA_MODE |
RADEON_VIPH_CONTROL_VIPH_EN );
OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT, RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS,
~RADEON_VIPH_TIMEOUT_STAT_AK_MASK & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS);
OUTREG( regs, RADEON_VIPH_DV_LAT,
0xff |
(4 << RADEON_VIPH_DV_LAT_VIPH_DV0_LAT_SHIFT) |
(4 << RADEON_VIPH_DV_LAT_VIPH_DV1_LAT_SHIFT) |
(4 << RADEON_VIPH_DV_LAT_VIPH_DV2_LAT_SHIFT) |
(4 << RADEON_VIPH_DV_LAT_VIPH_DV3_LAT_SHIFT));
OUTREG( regs, RADEON_VIPH_DMA_CHUNK,
1 |
(1 << RADEON_VIPH_DMA_CHUNK_VIPH_CH1_CHUNK_SHIFT) |
(1 << RADEON_VIPH_DMA_CHUNK_VIPH_CH2_CHUNK_SHIFT) |
(1 << RADEON_VIPH_DMA_CHUNK_VIPH_CH3_CHUNK_SHIFT));
OUTREGP( regs, RADEON_TEST_DEBUG_CNTL, 0, ~RADEON_TEST_DEBUG_CNTL_OUT_EN );
RELEASE_BEN( di->si->cp.lock );
}
// find VIP channel of a device
// return: >= 0 channel of device
// < 0 no device found
int Radeon_FindVIPDevice( device_info *di, uint32 device_id )
{
uint channel;
uint32 cur_device_id;
// if card has no VIP port, let hardware detection fail;
// in this case, noone will bother us again
if( !di->has_vip )
return -1;
VIPReset( di );
// there are up to 4 devices, connected to one of 4 channels
for( channel = 0; channel < 4; ++channel ) {
// read device id
if( !Radeon_VIPRead( di, channel, RADEON_VIP_VENDOR_DEVICE_ID, &cur_device_id ))
continue;
// compare device id directly
if( cur_device_id == device_id )
return channel;
}
// couldn't find device
return -1;
}
// check whether VIP host is idle
// lock must be hold
static status_t Radeon_VIPIdle( device_info *di )
{
vuint8 *regs = di->regs;
uint32 timeout;
//Radeon_WaitForIdle( di, false, false );
// if there is a stuck transaction, acknowledge that
timeout = INREG( regs, RADEON_VIPH_TIMEOUT_STAT );
if( (timeout & RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_STAT) != 0 ) {
OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT,
RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_AK,
~RADEON_VIPH_TIMEOUT_STAT_VIPH_REG_AK & ~RADEON_VIPH_TIMEOUT_STAT_AK_MASK );
if( (INREG( regs, RADEON_VIPH_CONTROL) & RADEON_VIPH_CONTROL_VIPH_REG_RDY) != 0 )
return B_BUSY;
else
return B_ERROR;
}
//Radeon_WaitForIdle( di, false, false );
if( (INREG( regs, RADEON_VIPH_CONTROL) & RADEON_VIPH_CONTROL_VIPH_REG_RDY) != 0 )
return B_BUSY;
else
return B_OK;
}
// wait until VIP host is idle
// lock must be hold
static bool Radeon_VIPWaitForIdle( device_info *di )
{
int i;
// wait 100x 1ms before giving up
for( i = 0; i < 100; ++i ) {
status_t res;
res = Radeon_VIPIdle( di );
if( res != B_BUSY ) {
if( res == B_OK )
return true;
else
return false;
}
snooze( 1000 );
}
return false;
}