From 5f6e3f515c38891bf243cc013f5faca7511708dc Mon Sep 17 00:00:00 2001 From: shadow303 Date: Tue, 20 Jul 2004 02:17:39 +0000 Subject: [PATCH] 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 --- .../drivers/graphics/radeon/CPMicroCode.h | 786 ++++++++++++++++++ .../kernel/drivers/graphics/radeon/CP_setup.c | 655 +++++++++++++++ .../kernel/drivers/graphics/radeon/DMA.c | 177 ++++ .../kernel/drivers/graphics/radeon/Jamfile | 14 +- .../kernel/drivers/graphics/radeon/PCI_GART.c | 279 +++++++ .../kernel/drivers/graphics/radeon/agp.c | 5 +- .../kernel/drivers/graphics/radeon/bios.c | 237 +++--- .../kernel/drivers/graphics/radeon/detect.c | 120 +-- .../kernel/drivers/graphics/radeon/dma.c | 328 -------- .../kernel/drivers/graphics/radeon/driver.c | 177 +++- .../kernel/drivers/graphics/radeon/init.c | 201 +++-- .../kernel/drivers/graphics/radeon/irq.c | 195 ++++- .../drivers/graphics/radeon/mem_controller.c | 193 +++++ .../kernel/drivers/graphics/radeon/memmgr.c | 255 ------ .../kernel/drivers/graphics/radeon/memmgr.h | 43 - .../drivers/graphics/radeon/pll_access.c | 66 ++ .../drivers/graphics/radeon/radeon_driver.h | 118 ++- .../kernel/drivers/graphics/radeon/utils.c | 26 + .../kernel/drivers/graphics/radeon/vip.c | 241 ++++++ 19 files changed, 3160 insertions(+), 956 deletions(-) create mode 100644 src/add-ons/kernel/drivers/graphics/radeon/CPMicroCode.h create mode 100644 src/add-ons/kernel/drivers/graphics/radeon/CP_setup.c create mode 100644 src/add-ons/kernel/drivers/graphics/radeon/DMA.c create mode 100644 src/add-ons/kernel/drivers/graphics/radeon/PCI_GART.c delete mode 100644 src/add-ons/kernel/drivers/graphics/radeon/dma.c create mode 100644 src/add-ons/kernel/drivers/graphics/radeon/mem_controller.c delete mode 100644 src/add-ons/kernel/drivers/graphics/radeon/memmgr.c delete mode 100644 src/add-ons/kernel/drivers/graphics/radeon/memmgr.h create mode 100644 src/add-ons/kernel/drivers/graphics/radeon/pll_access.c create mode 100644 src/add-ons/kernel/drivers/graphics/radeon/utils.c create mode 100644 src/add-ons/kernel/drivers/graphics/radeon/vip.c diff --git a/src/add-ons/kernel/drivers/graphics/radeon/CPMicroCode.h b/src/add-ons/kernel/drivers/graphics/radeon/CPMicroCode.h new file mode 100644 index 0000000000..f486ea096b --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/radeon/CPMicroCode.h @@ -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 diff --git a/src/add-ons/kernel/drivers/graphics/radeon/CP_setup.c b/src/add-ons/kernel/drivers/graphics/radeon/CP_setup.c new file mode 100644 index 0000000000..5d9d23a216 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/radeon/CP_setup.c @@ -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 + +#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; + } +} diff --git a/src/add-ons/kernel/drivers/graphics/radeon/DMA.c b/src/add-ons/kernel/drivers/graphics/radeon/DMA.c new file mode 100644 index 0000000000..5deea04fcd --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/radeon/DMA.c @@ -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 + +// 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; +} diff --git a/src/add-ons/kernel/drivers/graphics/radeon/Jamfile b/src/add-ons/kernel/drivers/graphics/radeon/Jamfile index 6f5ff16825..fcd32602c0 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/Jamfile +++ b/src/add-ons/kernel/drivers/graphics/radeon/Jamfile @@ -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 : diff --git a/src/add-ons/kernel/drivers/graphics/radeon/PCI_GART.c b/src/add-ons/kernel/drivers/graphics/radeon/PCI_GART.c new file mode 100644 index 0000000000..1a5e7bfef6 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/radeon/PCI_GART.c @@ -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 +#include +#include "mmio.h" +#include "buscntrl_regs.h" +#include "memcntrl_regs.h" +#include "cp_regs.h" +#include + + +#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 ); +} diff --git a/src/add-ons/kernel/drivers/graphics/radeon/agp.c b/src/add-ons/kernel/drivers/graphics/radeon/agp.c index 89bebf3e58..053319f92d 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/agp.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/agp.c @@ -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 ) diff --git a/src/add-ons/kernel/drivers/graphics/radeon/bios.c b/src/add-ons/kernel/drivers/graphics/radeon/bios.c index ba088965c8..c252c67e26 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/bios.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/bios.c @@ -13,30 +13,35 @@ */ #include "radeon_driver.h" -#include -#include -#include -#include -#include -#include -#include -//#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 #include 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 ); diff --git a/src/add-ons/kernel/drivers/graphics/radeon/detect.c b/src/add-ons/kernel/drivers/graphics/radeon/detect.c index 3ef3f58934..4f333ef7e6 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/detect.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/detect.c @@ -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 ); } diff --git a/src/add-ons/kernel/drivers/graphics/radeon/dma.c b/src/add-ons/kernel/drivers/graphics/radeon/dma.c deleted file mode 100644 index 7977148f6c..0000000000 --- a/src/add-ons/kernel/drivers/graphics/radeon/dma.c +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include - - -#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 ); -} diff --git a/src/add-ons/kernel/drivers/graphics/radeon/driver.c b/src/add-ons/kernel/drivers/graphics/radeon/driver.c index a49d1e0fbe..62f9638332 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/driver.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/driver.c @@ -8,21 +8,17 @@ */ #include "radeon_driver.h" -#ifdef ENABLE_LOGGING -#include "log_coll.h" -#endif #include #include #include #include #include -#include -#include +#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; } diff --git a/src/add-ons/kernel/drivers/graphics/radeon/init.c b/src/add-ons/kernel/drivers/graphics/radeon/init.c index be057eb187..a6de0bf247 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/init.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/init.c @@ -16,8 +16,8 @@ #include #include -#include -#include +#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 ); diff --git a/src/add-ons/kernel/drivers/graphics/radeon/irq.c b/src/add-ons/kernel/drivers/graphics/radeon/irq.c index 395fdeedad..e773433271 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/irq.c +++ b/src/add-ons/kernel/drivers/graphics/radeon/irq.c @@ -11,70 +11,132 @@ #include "radeon_driver.h" #include -#include -#include +#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; } diff --git a/src/add-ons/kernel/drivers/graphics/radeon/mem_controller.c b/src/add-ons/kernel/drivers/graphics/radeon/mem_controller.c new file mode 100644 index 0000000000..efce952148 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/radeon/mem_controller.c @@ -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" ); +} + diff --git a/src/add-ons/kernel/drivers/graphics/radeon/memmgr.c b/src/add-ons/kernel/drivers/graphics/radeon/memmgr.c deleted file mode 100644 index d27bc500eb..0000000000 --- a/src/add-ons/kernel/drivers/graphics/radeon/memmgr.c +++ /dev/null @@ -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 -#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" ); -} diff --git a/src/add-ons/kernel/drivers/graphics/radeon/memmgr.h b/src/add-ons/kernel/drivers/graphics/radeon/memmgr.h deleted file mode 100644 index 6faf7e0823..0000000000 --- a/src/add-ons/kernel/drivers/graphics/radeon/memmgr.h +++ /dev/null @@ -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 - - -// 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 diff --git a/src/add-ons/kernel/drivers/graphics/radeon/pll_access.c b/src/add-ons/kernel/drivers/graphics/radeon/pll_access.c new file mode 100644 index 0000000000..d76e7b2055 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/radeon/pll_access.c @@ -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 ); +} diff --git a/src/add-ons/kernel/drivers/graphics/radeon/radeon_driver.h b/src/add-ons/kernel/drivers/graphics/radeon/radeon_driver.h index 55085d53a1..7376502136 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon/radeon_driver.h +++ b/src/add-ons/kernel/drivers/graphics/radeon/radeon_driver.h @@ -10,7 +10,7 @@ #ifndef _RADEON_DRIVER_H #define _RADEON_DRIVER_H -#include +#include "radeon_interface.h" #include "memmgr.h" #include @@ -26,27 +26,39 @@ extern int debug_level_error; #define DEBUG_WAIT_ON_ERROR 1000000*/ #define DEBUG_MSG_PREFIX "Radeon - " -#include +#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 diff --git a/src/add-ons/kernel/drivers/graphics/radeon/utils.c b/src/add-ons/kernel/drivers/graphics/radeon/utils.c new file mode 100644 index 0000000000..05071e2755 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/radeon/utils.c @@ -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; +} diff --git a/src/add-ons/kernel/drivers/graphics/radeon/vip.c b/src/add-ons/kernel/drivers/graphics/radeon/vip.c new file mode 100644 index 0000000000..32cb819ded --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/radeon/vip.c @@ -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; +}