1428d7b3dSmrg/************************************************************************** 2428d7b3dSmrg 3428d7b3dSmrgCopyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. 4428d7b3dSmrgAll Rights Reserved. 5428d7b3dSmrg 6428d7b3dSmrgPermission is hereby granted, free of charge, to any person obtaining a 7428d7b3dSmrgcopy of this software and associated documentation files (the 8428d7b3dSmrg"Software"), to deal in the Software without restriction, including 9428d7b3dSmrgwithout limitation the rights to use, copy, modify, merge, publish, 10428d7b3dSmrgdistribute, sub license, and/or sell copies of the Software, and to 11428d7b3dSmrgpermit persons to whom the Software is furnished to do so, subject to 12428d7b3dSmrgthe following conditions: 13428d7b3dSmrg 14428d7b3dSmrgThe above copyright notice and this permission notice (including the 15428d7b3dSmrgnext paragraph) shall be included in all copies or substantial portions 16428d7b3dSmrgof the Software. 17428d7b3dSmrg 18428d7b3dSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19428d7b3dSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20428d7b3dSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21428d7b3dSmrgIN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR 22428d7b3dSmrgANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23428d7b3dSmrgTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24428d7b3dSmrgSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25428d7b3dSmrg 26428d7b3dSmrg**************************************************************************/ 27428d7b3dSmrg 28428d7b3dSmrg#ifdef HAVE_CONFIG_H 29428d7b3dSmrg#include "config.h" 30428d7b3dSmrg#endif 31428d7b3dSmrg 32428d7b3dSmrg/* 33428d7b3dSmrg * Authors: 34428d7b3dSmrg * Keith Whitwell <keith@tungstengraphics.com> 35428d7b3dSmrg * 36428d7b3dSmrg */ 37428d7b3dSmrg 38428d7b3dSmrg#include "xorg-server.h" 39428d7b3dSmrg#include "xf86.h" 40428d7b3dSmrg#include "xf86_OSproc.h" 41428d7b3dSmrg 42428d7b3dSmrg#include "i810.h" 43428d7b3dSmrg#include "i810_reg.h" 44428d7b3dSmrg 45428d7b3dSmrgint 46428d7b3dSmrgI810AllocLow(I810MemRange * result, I810MemRange * pool, int size) 47428d7b3dSmrg{ 48428d7b3dSmrg if (size > (long)pool->Size) 49428d7b3dSmrg return 0; 50428d7b3dSmrg 51428d7b3dSmrg pool->Size -= size; 52428d7b3dSmrg result->Size = size; 53428d7b3dSmrg result->Start = pool->Start; 54428d7b3dSmrg result->End = pool->Start += size; 55428d7b3dSmrg 56428d7b3dSmrg return 1; 57428d7b3dSmrg} 58428d7b3dSmrg 59428d7b3dSmrgint 60428d7b3dSmrgI810AllocHigh(I810MemRange * result, I810MemRange * pool, int size) 61428d7b3dSmrg{ 62428d7b3dSmrg if (size > (long)pool->Size) 63428d7b3dSmrg return 0; 64428d7b3dSmrg 65428d7b3dSmrg pool->Size -= size; 66428d7b3dSmrg result->Size = size; 67428d7b3dSmrg result->End = pool->End; 68428d7b3dSmrg result->Start = pool->End -= size; 69428d7b3dSmrg 70428d7b3dSmrg return 1; 71428d7b3dSmrg} 72428d7b3dSmrg 73428d7b3dSmrgint 74428d7b3dSmrgI810AllocateGARTMemory(ScrnInfoPtr pScrn) 75428d7b3dSmrg{ 76428d7b3dSmrg unsigned long size = pScrn->videoRam * 1024UL; 77428d7b3dSmrg I810Ptr pI810 = I810PTR(pScrn); 78428d7b3dSmrg int key; 79428d7b3dSmrg long tom = 0; 80428d7b3dSmrg unsigned long physical; 81428d7b3dSmrg 82428d7b3dSmrg if (!xf86AgpGARTSupported() || !xf86AcquireGART(pScrn->scrnIndex)) { 83428d7b3dSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 84428d7b3dSmrg "AGP GART support is either not available or cannot be used.\n" 85428d7b3dSmrg "\tMake sure your kernel has agpgart support or has the\n" 86428d7b3dSmrg "\tagpgart module loaded.\n"); 87428d7b3dSmrg return FALSE; 88428d7b3dSmrg } 89428d7b3dSmrg 90428d7b3dSmrg /* This allows the 2d only Xserver to regen */ 91428d7b3dSmrg pI810->agpAcquired2d = TRUE; 92428d7b3dSmrg 93428d7b3dSmrg /* 94428d7b3dSmrg * I810/I815 95428d7b3dSmrg * 96428d7b3dSmrg * Treat the gart like video memory - we assume we own all that is 97428d7b3dSmrg * there, so ignore EBUSY errors. Don't try to remove it on 98428d7b3dSmrg * failure, either, as other X server may be using it. 99428d7b3dSmrg */ 100428d7b3dSmrg 101428d7b3dSmrg if ((key = xf86AllocateGARTMemory(pScrn->scrnIndex, size, 0, NULL)) == -1) 102428d7b3dSmrg return FALSE; 103428d7b3dSmrg 104428d7b3dSmrg pI810->VramOffset = 0; 105428d7b3dSmrg pI810->VramKey = key; 106428d7b3dSmrg 107428d7b3dSmrg if (!xf86BindGARTMemory(pScrn->scrnIndex, key, 0)) 108428d7b3dSmrg return FALSE; 109428d7b3dSmrg 110428d7b3dSmrg pI810->SysMem.Start = 0; 111428d7b3dSmrg pI810->SysMem.Size = size; 112428d7b3dSmrg pI810->SysMem.End = size; 113428d7b3dSmrg pI810->SavedSysMem = pI810->SysMem; 114428d7b3dSmrg 115428d7b3dSmrg tom = pI810->SysMem.End; 116428d7b3dSmrg 117428d7b3dSmrg pI810->DcacheMem.Start = 0; 118428d7b3dSmrg pI810->DcacheMem.End = 0; 119428d7b3dSmrg pI810->DcacheMem.Size = 0; 120428d7b3dSmrg pI810->CursorPhysical = 0; 121428d7b3dSmrg pI810->CursorARGBPhysical = 0; 122428d7b3dSmrg 123428d7b3dSmrg /* 124428d7b3dSmrg * Dcache - half the speed of normal ram, so not really useful for 125428d7b3dSmrg * a 2d server. Don't bother reporting its presence. This is 126428d7b3dSmrg * mapped in addition to the requested amount of system ram. 127428d7b3dSmrg */ 128428d7b3dSmrg 129428d7b3dSmrg size = 1024 * 4096; 130428d7b3dSmrg 131428d7b3dSmrg /* 132428d7b3dSmrg * Keep it 512K aligned for the sake of tiled regions. 133428d7b3dSmrg */ 134428d7b3dSmrg 135428d7b3dSmrg tom += 0x7ffff; 136428d7b3dSmrg tom &= ~0x7ffff; 137428d7b3dSmrg 138428d7b3dSmrg if ((key = xf86AllocateGARTMemory(pScrn->scrnIndex, size, 1, NULL)) != -1) { 139428d7b3dSmrg pI810->DcacheOffset = tom; 140428d7b3dSmrg pI810->DcacheKey = key; 141428d7b3dSmrg if (!xf86BindGARTMemory(pScrn->scrnIndex, key, tom)) { 142428d7b3dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 143428d7b3dSmrg "Allocation of %ld bytes for DCACHE failed\n", size); 144428d7b3dSmrg pI810->DcacheKey = -1; 145428d7b3dSmrg } else { 146428d7b3dSmrg pI810->DcacheMem.Start = tom; 147428d7b3dSmrg pI810->DcacheMem.Size = size; 148428d7b3dSmrg pI810->DcacheMem.End = pI810->DcacheMem.Start + pI810->DcacheMem.Size; 149428d7b3dSmrg tom = pI810->DcacheMem.End; 150428d7b3dSmrg } 151428d7b3dSmrg } else { 152428d7b3dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 153428d7b3dSmrg "No physical memory available for %ld bytes of DCACHE\n", 154428d7b3dSmrg size); 155428d7b3dSmrg pI810->DcacheKey = -1; 156428d7b3dSmrg } 157428d7b3dSmrg 158428d7b3dSmrg /* 159428d7b3dSmrg * Mouse cursor -- The i810 (crazy) needs a physical address in 160428d7b3dSmrg * system memory from which to upload the cursor. We get this from 161428d7b3dSmrg * the agpgart module using a special memory type. 162428d7b3dSmrg */ 163428d7b3dSmrg 164428d7b3dSmrg /* 165428d7b3dSmrg * 4k for the cursor is excessive, I'm going to steal 3k for 166428d7b3dSmrg * overlay registers later 167428d7b3dSmrg */ 168428d7b3dSmrg 169428d7b3dSmrg size = 4096; 170428d7b3dSmrg 171428d7b3dSmrg if ((key = 172428d7b3dSmrg xf86AllocateGARTMemory(pScrn->scrnIndex, size, 2, &physical)) == -1) { 173428d7b3dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 174428d7b3dSmrg "No physical memory available for HW cursor\n"); 175428d7b3dSmrg pI810->HwcursKey = -1; 176428d7b3dSmrg pI810->CursorStart = 0; 177428d7b3dSmrg } else { 178428d7b3dSmrg pI810->HwcursOffset = tom; 179428d7b3dSmrg pI810->HwcursKey = key; 180428d7b3dSmrg if (!xf86BindGARTMemory(pScrn->scrnIndex, key, tom)) { 181428d7b3dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 182428d7b3dSmrg "Allocation of %ld bytes for HW cursor failed\n", size); 183428d7b3dSmrg pI810->HwcursKey = -1; 184428d7b3dSmrg } else { 185428d7b3dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 186428d7b3dSmrg "Allocated of %ld bytes for HW cursor\n", size); 187428d7b3dSmrg pI810->CursorPhysical = physical; 188428d7b3dSmrg pI810->CursorStart = tom; 189428d7b3dSmrg tom += size; 190428d7b3dSmrg } 191428d7b3dSmrg } 192428d7b3dSmrg 193428d7b3dSmrg /* 194428d7b3dSmrg * 16k for the ARGB cursor 195428d7b3dSmrg */ 196428d7b3dSmrg 197428d7b3dSmrg size = 16384; 198428d7b3dSmrg 199428d7b3dSmrg if ((key = 200428d7b3dSmrg xf86AllocateGARTMemory(pScrn->scrnIndex, size, 2, &physical)) == -1) { 201428d7b3dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 202428d7b3dSmrg "No physical memory available for ARGB HW cursor\n"); 203428d7b3dSmrg pI810->ARGBHwcursKey = -1; 204428d7b3dSmrg pI810->CursorARGBStart = 0; 205428d7b3dSmrg } else { 206428d7b3dSmrg pI810->ARGBHwcursOffset = tom; 207428d7b3dSmrg pI810->ARGBHwcursKey = key; 208428d7b3dSmrg if (!xf86BindGARTMemory(pScrn->scrnIndex, key, tom)) { 209428d7b3dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 210428d7b3dSmrg "Allocation of %ld bytes for ARGB HW cursor failed\n", size); 211428d7b3dSmrg pI810->ARGBHwcursKey = -1; 212428d7b3dSmrg } else { 213428d7b3dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 214428d7b3dSmrg "Allocated of %ld bytes for ARGB HW cursor\n", size); 215428d7b3dSmrg pI810->CursorARGBPhysical = physical; 216428d7b3dSmrg pI810->CursorARGBStart = tom; 217428d7b3dSmrg tom += size; 218428d7b3dSmrg } 219428d7b3dSmrg } 220428d7b3dSmrg 221428d7b3dSmrg /* 222428d7b3dSmrg * Overlay register buffer -- Just like the cursor, the i810 needs a 223428d7b3dSmrg * physical address in system memory from which to upload the overlay 224428d7b3dSmrg * registers. 225428d7b3dSmrg */ 226428d7b3dSmrg 227428d7b3dSmrg if (pI810->CursorStart != 0) { 228428d7b3dSmrg pI810->OverlayPhysical = pI810->CursorPhysical + 1024; 229428d7b3dSmrg pI810->OverlayStart = pI810->CursorStart + 1024; 230428d7b3dSmrg } 231428d7b3dSmrg 232428d7b3dSmrg pI810->GttBound = 1; 233428d7b3dSmrg 234428d7b3dSmrg return TRUE; 235428d7b3dSmrg} 236428d7b3dSmrg 237428d7b3dSmrg/* Tiled memory is good... really, really good... 238428d7b3dSmrg * 239428d7b3dSmrg * Need to make it less likely that we miss out on this - probably 240428d7b3dSmrg * need to move the frontbuffer away from the 'guarenteed' alignment 241428d7b3dSmrg * of the first memory segment, or perhaps allocate a discontigous 242428d7b3dSmrg * framebuffer to get more alignment 'sweet spots'. 243428d7b3dSmrg */ 244428d7b3dSmrgvoid 245428d7b3dSmrgI810SetTiledMemory(ScrnInfoPtr pScrn, int nr, unsigned int start, 246428d7b3dSmrg unsigned int pitch, unsigned int size) 247428d7b3dSmrg{ 248428d7b3dSmrg I810Ptr pI810 = I810PTR(pScrn); 249428d7b3dSmrg I810RegPtr i810Reg = &pI810->ModeReg; 250428d7b3dSmrg uint32_t val; 251428d7b3dSmrg uint32_t fence_mask = 0; 252428d7b3dSmrg 253428d7b3dSmrg if (nr < 0 || nr > 7) { 254428d7b3dSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "%s - fence %d out of range\n", 255428d7b3dSmrg "I810SetTiledMemory", nr); 256428d7b3dSmrg return; 257428d7b3dSmrg } 258428d7b3dSmrg 259428d7b3dSmrg i810Reg->Fence[nr] = 0; 260428d7b3dSmrg 261428d7b3dSmrg fence_mask = ~FENCE_START_MASK; 262428d7b3dSmrg 263428d7b3dSmrg if (start & fence_mask) { 264428d7b3dSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 265428d7b3dSmrg "%s %d: start (%x) is not 512k aligned\n", 266428d7b3dSmrg "I810SetTiledMemory", nr, start); 267428d7b3dSmrg return; 268428d7b3dSmrg } 269428d7b3dSmrg 270428d7b3dSmrg if (start % size) { 271428d7b3dSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 272428d7b3dSmrg "%s %d: start (%x) is not size (%x) aligned\n", 273428d7b3dSmrg "I810SetTiledMemory", nr, start, size); 274428d7b3dSmrg return; 275428d7b3dSmrg } 276428d7b3dSmrg 277428d7b3dSmrg if (pitch & 127) { 278428d7b3dSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 279428d7b3dSmrg "%s %d: pitch (%x) not a multiple of 128 bytes\n", 280428d7b3dSmrg "I810SetTiledMemory", nr, pitch); 281428d7b3dSmrg return; 282428d7b3dSmrg } 283428d7b3dSmrg 284428d7b3dSmrg val = (start | FENCE_X_MAJOR | FENCE_VALID); 285428d7b3dSmrg 286428d7b3dSmrg switch (size) { 287428d7b3dSmrg case KB(512): 288428d7b3dSmrg val |= FENCE_SIZE_512K; 289428d7b3dSmrg break; 290428d7b3dSmrg case MB(1): 291428d7b3dSmrg val |= FENCE_SIZE_1M; 292428d7b3dSmrg break; 293428d7b3dSmrg case MB(2): 294428d7b3dSmrg val |= FENCE_SIZE_2M; 295428d7b3dSmrg break; 296428d7b3dSmrg case MB(4): 297428d7b3dSmrg val |= FENCE_SIZE_4M; 298428d7b3dSmrg break; 299428d7b3dSmrg case MB(8): 300428d7b3dSmrg val |= FENCE_SIZE_8M; 301428d7b3dSmrg break; 302428d7b3dSmrg case MB(16): 303428d7b3dSmrg val |= FENCE_SIZE_16M; 304428d7b3dSmrg break; 305428d7b3dSmrg case MB(32): 306428d7b3dSmrg val |= FENCE_SIZE_32M; 307428d7b3dSmrg break; 308428d7b3dSmrg default: 309428d7b3dSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 310428d7b3dSmrg "%s %d: illegal size (0x%x)\n", "I810SetTiledMemory", nr, 311428d7b3dSmrg size); 312428d7b3dSmrg return; 313428d7b3dSmrg } 314428d7b3dSmrg 315428d7b3dSmrg switch (pitch / 128) { 316428d7b3dSmrg case 1: 317428d7b3dSmrg val |= FENCE_PITCH_1; 318428d7b3dSmrg break; 319428d7b3dSmrg case 2: 320428d7b3dSmrg val |= FENCE_PITCH_2; 321428d7b3dSmrg break; 322428d7b3dSmrg case 4: 323428d7b3dSmrg val |= FENCE_PITCH_4; 324428d7b3dSmrg break; 325428d7b3dSmrg case 8: 326428d7b3dSmrg val |= FENCE_PITCH_8; 327428d7b3dSmrg break; 328428d7b3dSmrg case 16: 329428d7b3dSmrg val |= FENCE_PITCH_16; 330428d7b3dSmrg break; 331428d7b3dSmrg case 32: 332428d7b3dSmrg val |= FENCE_PITCH_32; 333428d7b3dSmrg break; 334428d7b3dSmrg default: 335428d7b3dSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 336428d7b3dSmrg "%s %d: illegal size (0x%x)\n", "I810SetTiledMemory", nr, 337428d7b3dSmrg size); 338428d7b3dSmrg return; 339428d7b3dSmrg } 340428d7b3dSmrg 341428d7b3dSmrg i810Reg->Fence[nr] = val; 342428d7b3dSmrg} 343428d7b3dSmrg 344428d7b3dSmrgBool 345428d7b3dSmrgI810BindGARTMemory(ScrnInfoPtr pScrn) 346428d7b3dSmrg{ 347428d7b3dSmrg I810Ptr pI810 = I810PTR(pScrn); 348428d7b3dSmrg 349428d7b3dSmrg if (xf86AgpGARTSupported() && !pI810->directRenderingEnabled 350428d7b3dSmrg && !pI810->GttBound) { 351428d7b3dSmrg if (!xf86AcquireGART(pScrn->scrnIndex)) 352428d7b3dSmrg return FALSE; 353428d7b3dSmrg 354428d7b3dSmrg if (pI810->VramKey != -1 355428d7b3dSmrg && !xf86BindGARTMemory(pScrn->scrnIndex, pI810->VramKey, 356428d7b3dSmrg pI810->VramOffset)) 357428d7b3dSmrg return FALSE; 358428d7b3dSmrg 359428d7b3dSmrg if (pI810->DcacheKey != -1 360428d7b3dSmrg && !xf86BindGARTMemory(pScrn->scrnIndex, pI810->DcacheKey, 361428d7b3dSmrg pI810->DcacheOffset)) 362428d7b3dSmrg return FALSE; 363428d7b3dSmrg 364428d7b3dSmrg if (pI810->HwcursKey != -1 365428d7b3dSmrg && !xf86BindGARTMemory(pScrn->scrnIndex, pI810->HwcursKey, 366428d7b3dSmrg pI810->HwcursOffset)) 367428d7b3dSmrg return FALSE; 368428d7b3dSmrg 369428d7b3dSmrg if (pI810->ARGBHwcursKey != -1 370428d7b3dSmrg && !xf86BindGARTMemory(pScrn->scrnIndex, pI810->ARGBHwcursKey, 371428d7b3dSmrg pI810->ARGBHwcursOffset)) 372428d7b3dSmrg return FALSE; 373428d7b3dSmrg 374428d7b3dSmrg pI810->GttBound = 1; 375428d7b3dSmrg } 376428d7b3dSmrg 377428d7b3dSmrg return TRUE; 378428d7b3dSmrg} 379428d7b3dSmrg 380428d7b3dSmrgBool 381428d7b3dSmrgI810UnbindGARTMemory(ScrnInfoPtr pScrn) 382428d7b3dSmrg{ 383428d7b3dSmrg I810Ptr pI810 = I810PTR(pScrn); 384428d7b3dSmrg 385428d7b3dSmrg if (xf86AgpGARTSupported() && !pI810->directRenderingEnabled 386428d7b3dSmrg && pI810->GttBound) { 387428d7b3dSmrg if (pI810->VramKey != -1 388428d7b3dSmrg && !xf86UnbindGARTMemory(pScrn->scrnIndex, pI810->VramKey)) 389428d7b3dSmrg return FALSE; 390428d7b3dSmrg 391428d7b3dSmrg if (pI810->DcacheKey != -1 392428d7b3dSmrg && !xf86UnbindGARTMemory(pScrn->scrnIndex, pI810->DcacheKey)) 393428d7b3dSmrg return FALSE; 394428d7b3dSmrg 395428d7b3dSmrg if (pI810->HwcursKey != -1 396428d7b3dSmrg && !xf86UnbindGARTMemory(pScrn->scrnIndex, pI810->HwcursKey)) 397428d7b3dSmrg return FALSE; 398428d7b3dSmrg 399428d7b3dSmrg if (pI810->ARGBHwcursKey != -1 400428d7b3dSmrg && !xf86UnbindGARTMemory(pScrn->scrnIndex, pI810->ARGBHwcursKey)) 401428d7b3dSmrg return FALSE; 402428d7b3dSmrg 403428d7b3dSmrg if (!xf86ReleaseGART(pScrn->scrnIndex)) 404428d7b3dSmrg return FALSE; 405428d7b3dSmrg 406428d7b3dSmrg pI810->GttBound = 0; 407428d7b3dSmrg } 408428d7b3dSmrg 409428d7b3dSmrg return TRUE; 410428d7b3dSmrg} 411428d7b3dSmrg 412428d7b3dSmrgint 413428d7b3dSmrgI810CheckAvailableMemory(ScrnInfoPtr pScrn) 414428d7b3dSmrg{ 415428d7b3dSmrg AgpInfoPtr agpinf; 416428d7b3dSmrg int maxPages; 417428d7b3dSmrg 418428d7b3dSmrg if (!xf86AgpGARTSupported() || 419428d7b3dSmrg !xf86AcquireGART(pScrn->scrnIndex) || 420428d7b3dSmrg (agpinf = xf86GetAGPInfo(pScrn->scrnIndex)) == NULL || 421428d7b3dSmrg !xf86ReleaseGART(pScrn->scrnIndex)) 422428d7b3dSmrg return -1; 423428d7b3dSmrg 424428d7b3dSmrg maxPages = agpinf->totalPages - agpinf->usedPages; 425428d7b3dSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "%s: %dk available\n", 426428d7b3dSmrg "I810CheckAvailableMemory", maxPages * 4); 427428d7b3dSmrg 428428d7b3dSmrg return maxPages * 4; 429428d7b3dSmrg} 430