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:
parent
51c74f5a0c
commit
5f6e3f515c
786
src/add-ons/kernel/drivers/graphics/radeon/CPMicroCode.h
Normal file
786
src/add-ons/kernel/drivers/graphics/radeon/CPMicroCode.h
Normal 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
|
655
src/add-ons/kernel/drivers/graphics/radeon/CP_setup.c
Normal file
655
src/add-ons/kernel/drivers/graphics/radeon/CP_setup.c
Normal 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;
|
||||
}
|
||||
}
|
177
src/add-ons/kernel/drivers/graphics/radeon/DMA.c
Normal file
177
src/add-ons/kernel/drivers/graphics/radeon/DMA.c
Normal 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;
|
||||
}
|
@ -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 :
|
||||
|
279
src/add-ons/kernel/drivers/graphics/radeon/PCI_GART.c
Normal file
279
src/add-ons/kernel/drivers/graphics/radeon/PCI_GART.c
Normal 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 );
|
||||
}
|
@ -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 )
|
||||
|
@ -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 );
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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 );
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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 );
|
||||
|
@ -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;
|
||||
}
|
||||
|
193
src/add-ons/kernel/drivers/graphics/radeon/mem_controller.c
Normal file
193
src/add-ons/kernel/drivers/graphics/radeon/mem_controller.c
Normal 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" );
|
||||
}
|
||||
|
@ -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" );
|
||||
}
|
@ -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
|
66
src/add-ons/kernel/drivers/graphics/radeon/pll_access.c
Normal file
66
src/add-ons/kernel/drivers/graphics/radeon/pll_access.c
Normal 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 );
|
||||
}
|
@ -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
|
||||
|
26
src/add-ons/kernel/drivers/graphics/radeon/utils.c
Normal file
26
src/add-ons/kernel/drivers/graphics/radeon/utils.c
Normal 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;
|
||||
}
|
241
src/add-ons/kernel/drivers/graphics/radeon/vip.c
Normal file
241
src/add-ons/kernel/drivers/graphics/radeon/vip.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user