From fbe5f5e77ec086c5b9997d55f0e0dd2e23651b2a Mon Sep 17 00:00:00 2001 From: "Sergey Semyonov (Serge)" Date: Mon, 26 Oct 2009 22:40:01 +0000 Subject: [PATCH] kms: frontend, loader, kms complete git-svn-id: svn://kolibrios.org@1239 a494cfbc-eb01-0410-851d-a64ba20cac60 --- drivers/video/drm/includes/syscall.h | 30 ++- drivers/video/drm/radeon/atikms.asm | 33 +++- drivers/video/drm/radeon/pci.c | 65 +++++++ drivers/video/drm/radeon/radeon.h | 4 +- drivers/video/drm/radeon/radeon_device.c | 172 +++++++++++------ drivers/video/drm/radeon/rdisplay.c | 223 ++++++++++++++++++----- 6 files changed, 406 insertions(+), 121 deletions(-) diff --git a/drivers/video/drm/includes/syscall.h b/drivers/video/drm/includes/syscall.h index c0397e4b69..deee7c24ee 100644 --- a/drivers/video/drm/includes/syscall.h +++ b/drivers/video/drm/includes/syscall.h @@ -103,7 +103,7 @@ int dbgprintf(const char* format, ...); /////////////////////////////////////////////////////////////////////////////// -extern inline int GetScreenSize() +static inline int GetScreenSize() { int retval; @@ -113,7 +113,7 @@ extern inline int GetScreenSize() return retval; } -extern inline int GetScreenBpp() +static inline int GetScreenBpp() { int retval; @@ -123,7 +123,7 @@ extern inline int GetScreenBpp() return retval; } -extern inline int GetScreenPitch() +static inline int GetScreenPitch() { int retval; @@ -133,7 +133,7 @@ extern inline int GetScreenPitch() return retval; } -extern inline u32_t GetPgAddr(void *mem) +static inline u32_t GetPgAddr(void *mem) { u32_t retval; @@ -144,7 +144,7 @@ extern inline u32_t GetPgAddr(void *mem) return retval; }; -extern inline void CommitPages(void *mem, u32_t page, u32_t size) +static inline void CommitPages(void *mem, u32_t page, u32_t size) { size = (size+4095) & ~4095; __asm__ __volatile__ ( @@ -154,7 +154,7 @@ extern inline void CommitPages(void *mem, u32_t page, u32_t size) __asm__ __volatile__ ("":::"eax","ebx","ecx"); }; -extern inline void UnmapPages(void *mem, size_t size) +static inline void UnmapPages(void *mem, size_t size) { size = (size+4095) & ~4095; __asm__ __volatile__ ( @@ -164,7 +164,7 @@ extern inline void UnmapPages(void *mem, size_t size) __asm__ __volatile__ ("":::"eax","ecx"); }; -extern inline void usleep(u32_t delay) +static inline void usleep(u32_t delay) { if( !delay ) delay++; @@ -257,6 +257,22 @@ u32 __RegService(char *name, srv_proc_t proc) }; */ + +static inline u32_t GetService(const char *name) +{ + u32_t handle; + + __asm__ __volatile__ + ( + "pushl %%eax \n\t" + "call *__imp__GetService" + :"=eax" (handle) + :"a" (name) + :"ebx","ecx","edx","esi", "edi" + ); + return handle; +}; + static inline u32_t safe_cli(void) { u32_t ifl; diff --git a/drivers/video/drm/radeon/atikms.asm b/drivers/video/drm/radeon/atikms.asm index ff48074257..fb6f684d12 100644 --- a/drivers/video/drm/radeon/atikms.asm +++ b/drivers/video/drm/radeon/atikms.asm @@ -7,23 +7,40 @@ dd start dd i_end dd mem dd mem -dd 0 -dd 0 +dd cmdline +dd path start: + mov eax, 68 + mov ebx, 16 + mov ecx, sz_display + int 0x40 + test eax, eax + jnz .done ; FIXME parse command line and + ; call service + + xor eax, eax + mov ecx, 1024 + mov edi, path + cld + repne scasb + dec edi + mov [edi], dword '.dll' + mov [edi+4], al mov eax, 68 mov ebx, 21 - mov ecx, sz_kms - mov edx, sz_mode + mov ecx, path + mov edx, cmdline int 0x40 - +.done: mov eax, -1 int 0x40 -sz_kms db '/rd/1/drivers/atikms.dll',0 -sz_mode db '-m 1024x768 -l/hd0/2/atikms.log',0 +sz_display db 'DISPLAY',0 align 4 i_end: -rb 16 +cmdline rb 256 +path rb 1024 + rb 16 ; stack mem: diff --git a/drivers/video/drm/radeon/pci.c b/drivers/video/drm/radeon/pci.c index e1c9092d6f..69544b0578 100644 --- a/drivers/video/drm/radeon/pci.c +++ b/drivers/video/drm/radeon/pci.c @@ -445,6 +445,71 @@ int enum_pci_devices() return 0; } +#define PCI_FIND_CAP_TTL 48 + +static int __pci_find_next_cap_ttl(unsigned int bus, unsigned int devfn, + u8 pos, int cap, int *ttl) +{ + u8 id; + + while ((*ttl)--) { + pos = PciRead8(bus, devfn, pos); + if (pos < 0x40) + break; + pos &= ~3; + id = PciRead8(bus, devfn, pos + PCI_CAP_LIST_ID); + if (id == 0xff) + break; + if (id == cap) + return pos; + pos += PCI_CAP_LIST_NEXT; + } + return 0; +} + +static int __pci_find_next_cap(unsigned int bus, unsigned int devfn, + u8 pos, int cap) +{ + int ttl = PCI_FIND_CAP_TTL; + + return __pci_find_next_cap_ttl(bus, devfn, pos, cap, &ttl); +} + +static int __pci_bus_find_cap_start(unsigned int bus, + unsigned int devfn, u8 hdr_type) +{ + u16 status; + + status = PciRead16(bus, devfn, PCI_STATUS); + if (!(status & PCI_STATUS_CAP_LIST)) + return 0; + + switch (hdr_type) { + case PCI_HEADER_TYPE_NORMAL: + case PCI_HEADER_TYPE_BRIDGE: + return PCI_CAPABILITY_LIST; + case PCI_HEADER_TYPE_CARDBUS: + return PCI_CB_CAPABILITY_LIST; + default: + return 0; + } + + return 0; +} + + +int pci_find_capability(struct pci_dev *dev, int cap) +{ + int pos; + + pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type); + if (pos) + pos = __pci_find_next_cap(dev->bus, dev->devfn, pos, cap); + + return pos; +} + + #if 0 /** * pci_set_power_state - Set the power state of a PCI device diff --git a/drivers/video/drm/radeon/radeon.h b/drivers/video/drm/radeon/radeon.h index 84282793e4..3bd874ef54 100644 --- a/drivers/video/drm/radeon/radeon.h +++ b/drivers/video/drm/radeon/radeon.h @@ -1139,8 +1139,8 @@ drm_get_resource_start(struct drm_device *dev, unsigned int resource); resource_size_t drm_get_resource_len(struct drm_device *dev, unsigned int resource); -bool set_mode(struct drm_device *dev, int width, int height); - +bool set_mode(struct drm_device *dev, struct drm_connector *connector, + mode_t *mode, bool strict); #endif diff --git a/drivers/video/drm/radeon/radeon_device.c b/drivers/video/drm/radeon/radeon_device.c index 1eb6cd72fe..757f5c53a3 100644 --- a/drivers/video/drm/radeon/radeon_device.c +++ b/drivers/video/drm/radeon/radeon_device.c @@ -48,6 +48,9 @@ int radeon_tv = 0; void parse_cmdline(char *cmdline, mode_t *mode, char *log); int init_display(struct radeon_device *rdev, mode_t *mode); +int get_modes(mode_t *mode, int *count); +int set_user_mode(mode_t *mode); + /* Legacy VGA regions */ #define VGA_RSRC_NONE 0x00 @@ -646,58 +649,6 @@ int radeon_device_init(struct radeon_device *rdev, } -static struct pci_device_id pciidlist[] = { - radeon_PCI_IDS -}; - -mode_t usermode; -char log[256]; - -u32_t drvEntry(int action, char *cmdline) -{ - struct pci_device_id *ent; - - dev_t device; - int err; - u32_t retval = 0; - - if(action != 1) - return 0; - - if( cmdline && *cmdline ) - parse_cmdline(cmdline, &usermode, log); - - if(!dbg_open(log)) - { - strcpy(log, "/rd/1/drivers/atikms.log"); - - if(!dbg_open(log)) - { - printf("Can't open %s\nExit\n", log); - return 0; - }; - } - - enum_pci_devices(); - - ent = find_pci_device(&device, pciidlist); - - if( unlikely(ent == NULL) ) - { - dbgprintf("device not found\n"); - return 0; - }; - - dbgprintf("device %x:%x\n", device.pci_dev.vendor, - device.pci_dev.device); - - err = drm_get_dev(&device.pci_dev, ent); - - return retval; -}; - - - /* * Driver load/unload */ @@ -716,13 +667,13 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) dev->dev_private = (void *)rdev; /* update BUS flag */ -// if (drm_device_is_agp(dev)) { + if (drm_device_is_agp(dev)) { flags |= RADEON_IS_AGP; -// } else if (drm_device_is_pcie(dev)) { -// flags |= RADEON_IS_PCIE; -// } else { -// flags |= RADEON_IS_PCI; -// } + } else if (drm_device_is_pcie(dev)) { + flags |= RADEON_IS_PCIE; + } else { + flags |= RADEON_IS_PCI; + } /* radeon_device_init should report only fatal error * like memory allocation failure or iomapping failure, @@ -746,6 +697,8 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) return 0; } +mode_t usermode; + int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -848,3 +801,106 @@ uint32_t __div64_32(uint64_t *n, uint32_t base) return rem; } + +static struct pci_device_id pciidlist[] = { + radeon_PCI_IDS +}; + + +#define API_VERSION 0x01000100 + +#define SRV_GETVERSION 0 +#define SRV_ENUM_MODES 1 +#define SRV_SET_MODE 2 + +int _stdcall display_handler(ioctl_t *io) +{ + int retval = -1; + u32_t *inp; + u32_t *outp; + + inp = io->input; + outp = io->output; + + switch(io->io_code) + { + case SRV_GETVERSION: + if(io->out_size==4) + { + *outp = API_VERSION; + retval = 0; + } + break; + + case SRV_ENUM_MODES: + dbgprintf("SRV_ENUM_MODES inp %x inp_size %x out_size %x\n", + inp, io->inp_size, io->out_size ); + + if( (outp != NULL) && (io->out_size == 4) && + (io->inp_size == *outp * sizeof(mode_t)) ) + { + retval = get_modes((mode_t*)inp, outp); + }; + break; + + case SRV_SET_MODE: + if( (inp != NULL) && + (io->inp_size == sizeof(mode_t)) ) + { + retval = set_user_mode((mode_t*)inp); + }; + break; + + }; + + return retval; +} + +u32_t drvEntry(int action, char *cmdline) +{ + static char log[256]; + + struct pci_device_id *ent; + + dev_t device; + int err; + u32_t retval = 0; + + if(action != 1) + return 0; + + if( GetService("DISPLAY") != 0 ) + return 0; + + if( cmdline && *cmdline ) + parse_cmdline(cmdline, &usermode, log); + + if(!dbg_open(log)) + { + strcpy(log, "/rd/1/drivers/atikms.log"); + + if(!dbg_open(log)) + { + printf("Can't open %s\nExit\n", log); + return 0; + }; + } + + enum_pci_devices(); + + ent = find_pci_device(&device, pciidlist); + + if( unlikely(ent == NULL) ) + { + dbgprintf("device not found\n"); + return 0; + }; + + dbgprintf("device %x:%x\n", device.pci_dev.vendor, + device.pci_dev.device); + + err = drm_get_dev(&device.pci_dev, ent); + + return RegService("DISPLAY", display_handler); + +}; diff --git a/drivers/video/drm/radeon/rdisplay.c b/drivers/video/drm/radeon/rdisplay.c index ee4b7d716a..28f4886782 100644 --- a/drivers/video/drm/radeon/rdisplay.c +++ b/drivers/video/drm/radeon/rdisplay.c @@ -50,7 +50,9 @@ struct tag_display int pitch; int lfb; + int supported_modes; struct drm_device *ddev; + struct drm_connector *connector; struct drm_crtc *crtc; struct list_head cursors; @@ -284,44 +286,52 @@ static char *manufacturer_name(unsigned char *x) return name; } -bool set_mode(struct drm_device *dev, int width, int height) +bool set_mode(struct drm_device *dev, struct drm_connector *connector, + mode_t *reqmode, bool strict) { - struct drm_connector *connector; + struct drm_display_mode *mode = NULL, *tmpmode; bool ret = false; ENTER(); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) + list_for_each_entry(tmpmode, &connector->modes, head) { - struct drm_display_mode *mode; + if( (drm_mode_width(tmpmode) == reqmode->width) && + (drm_mode_height(tmpmode) == reqmode->height) && + (drm_mode_vrefresh(tmpmode) == reqmode->freq) ) + { + mode = tmpmode; + break; + } + }; + if( (mode == NULL) && (strict == false) ) + { + list_for_each_entry(tmpmode, &connector->modes, head) + { + if( (drm_mode_width(tmpmode) == reqmode->width) && + (drm_mode_height(tmpmode) == reqmode->height) ) + { + mode = tmpmode; + break; + } + }; + }; + + if( mode != NULL ) + { + struct drm_framebuffer *fb; struct drm_encoder *encoder; struct drm_crtc *crtc; - if( connector->status != connector_status_connected) - continue; + char con_edid[128]; + char *con_name; + char *enc_name; encoder = connector->encoder; - if( encoder == NULL) - continue; - crtc = encoder->crtc; - if(crtc == NULL) - continue; - - list_for_each_entry(mode, &connector->modes, head) - { - char *con_name, *enc_name; - - struct drm_framebuffer *fb; - - if (drm_mode_width(mode) == width && - drm_mode_height(mode) == height) - { - char con_edid[128]; - fb = list_first_entry(&dev->mode_config.fb_kernel_list, struct drm_framebuffer, filp_head); @@ -338,11 +348,11 @@ bool set_mode(struct drm_device *dev, int width, int height) enc_name = drm_get_encoder_name(encoder); dbgprintf("set mode %d %d connector %s encoder %s\n", - width, height, con_name, enc_name); + reqmode->width, reqmode->height, con_name, enc_name); - fb->width = width; - fb->height = height; - fb->pitch = radeon_align_pitch(dev->dev_private, width, 32, false) * ((32 + 1) / 8); + fb->width = reqmode->width; + fb->height = reqmode->height; + fb->pitch = radeon_align_pitch(dev->dev_private, reqmode->width, 32, false) * ((32 + 1) / 8); crtc->fb = fb; crtc->enabled = true; @@ -350,55 +360,114 @@ bool set_mode(struct drm_device *dev, int width, int height) ret = drm_crtc_helper_set_mode(crtc, mode, 0, 0, fb); + if (ret == true) + { rdisplay->width = fb->width; rdisplay->height = fb->height; rdisplay->pitch = fb->pitch; + rdisplay->vrefresh = drm_mode_vrefresh(mode); sysSetScreen(fb->width, fb->height, fb->pitch); - if (ret == true) - { - dbgprintf("new mode %d %d pitch %d\n",fb->width, fb->height, fb->pitch); + dbgprintf("new mode %d x %d pitch %d\n", + fb->width, fb->height, fb->pitch); } else - { DRM_ERROR("failed to set mode %d_%d on crtc %p\n", fb->width, fb->height, crtc); - }; + } - LEAVE(); - - return ret; - }; - } - }; LEAVE(); return ret; }; - -int init_display(struct radeon_device *rdev, mode_t *usermode) +static int count_connector_modes(struct drm_connector* connector) { + struct drm_display_mode *mode; + int count = 0; + + list_for_each_entry(mode, &connector->modes, head) + { + count++; + }; + return count; +}; + +static struct drm_connector* get_def_connector(struct drm_device *dev) +{ + struct drm_connector *connector; + struct drm_connector *def_connector = NULL; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) + { + struct drm_encoder *encoder; + struct drm_crtc *crtc; + + if( connector->status != connector_status_connected) + continue; + + encoder = connector->encoder; + if( encoder == NULL) + continue; + + if( encoder->encoder_type == DRM_MODE_ENCODER_TVDAC ) + { + dbgprintf("skip tvdac encoder %s connector %s\n", + drm_get_encoder_name(encoder), + drm_get_connector_name(connector)); + continue; + }; + + crtc = encoder->crtc; + if(crtc == NULL) + continue; + + def_connector = connector; + break; + }; + + return def_connector; +}; + +bool init_display(struct radeon_device *rdev, mode_t *usermode) +{ + struct drm_device *dev; cursor_t *cursor; + bool retval = false; ENTER(); rdisplay = GetDisplay(); - rdisplay->ddev = rdev->ddev; + dev = rdisplay->ddev = rdev->ddev; list_for_each_entry(cursor, &rdisplay->cursors, list) { init_cursor(cursor); }; + rdisplay->connector = get_def_connector(dev); + + if( rdisplay->connector == 0 ) + return false; + + rdisplay->supported_modes = count_connector_modes(rdisplay->connector); + if( (usermode->width != 0) && (usermode->height != 0) ) { - set_mode(rdev->ddev, usermode->width, usermode->height); + retval = set_mode(dev, rdisplay->connector, usermode, false); } else - set_mode(rdev->ddev, 800, 600); + { + mode_t mode; + mode.width = rdisplay->width; + mode.height = rdisplay->height; + mode.bpp = 32; + mode.freq = 60; + + retval = set_mode(dev, rdisplay->connector, &mode, false); + }; select_cursor(rdisplay->cursor); radeon_show_cursor(rdisplay->crtc); @@ -411,7 +480,7 @@ int init_display(struct radeon_device *rdev, mode_t *usermode) LEAVE(); - return 1; + return retval; }; static int my_atoi(char **cmd) @@ -442,12 +511,17 @@ char* parse_mode(char *p, mode_t *mode) p--; mode->width = my_atoi(&p); - p++; + if(*p == 'x') p++; mode->height = my_atoi(&p); - p++; + if(*p == 'x') p++; + + mode->bpp = 32; mode->freq = my_atoi(&p); + + if( mode->freq == 0 ) + mode->freq = 60; } return p; @@ -490,3 +564,60 @@ void parse_cmdline(char *cmdline, mode_t *mode, char *log) }; }; + +int get_modes(mode_t *mode, int *count) +{ + int err = -1; + + ENTER(); + + dbgprintf("mode %x count %d\n", mode, *count); + + if( *count == 0 ) + { + *count = rdisplay->supported_modes; + err = 0; + } + else if( mode != NULL ) + { + struct drm_display_mode *drmmode; + int i = 0; + + if( *count > rdisplay->supported_modes) + *count = rdisplay->supported_modes; + + list_for_each_entry(drmmode, &rdisplay->connector->modes, head) + { + if( i < *count) + { + mode->width = drm_mode_width(drmmode); + mode->height = drm_mode_height(drmmode); + mode->bpp = 32; + mode->freq = drm_mode_vrefresh(drmmode); + i++; + mode++; + } + else break; + }; + *count = i; + err = 0; + }; + LEAVE(); + return err; +} + + +int set_user_mode(mode_t *mode) +{ + int err = -1; + + if( (mode->width != 0) && + (mode->height != 0) && + (mode->freq != 0 ) ) + { + if( set_mode(rdisplay->ddev, rdisplay->connector, mode, true) ) + err = 0; + }; + + return err; +};