static unsigned int mga_warp_g200_microcode_size( drm_mga_private_t *dev_priv ) { unsigned int size; size = ( WARP_UCODE_SIZE( warp_g200_tgz ) + WARP_UCODE_SIZE( warp_g200_tgza ) + WARP_UCODE_SIZE( warp_g200_tgzaf ) + WARP_UCODE_SIZE( warp_g200_tgzf ) + WARP_UCODE_SIZE( warp_g200_tgzs ) + WARP_UCODE_SIZE( warp_g200_tgzsa ) + WARP_UCODE_SIZE( warp_g200_tgzsaf ) + WARP_UCODE_SIZE( warp_g200_tgzsf ) ); size = PAGE_ALIGN( size ); DRM_DEBUG( "G200 ucode size = %d bytes\n", size ); return size; }
int mga_warp_install_microcode(drm_mga_private_t *dev_priv) { unsigned char *vcbase = dev_priv->warp->handle; unsigned long pcbase = dev_priv->warp->offset; const char *firmware_name; struct platform_device *pdev; const struct firmware *fw = NULL; const struct ihex_binrec *rec; unsigned int size; int n_pipes, where; int rc = 0; switch (dev_priv->chipset) { case MGA_CARD_TYPE_G400: case MGA_CARD_TYPE_G550: firmware_name = FIRMWARE_G400; n_pipes = MGA_MAX_G400_PIPES; break; case MGA_CARD_TYPE_G200: firmware_name = FIRMWARE_G200; n_pipes = MGA_MAX_G200_PIPES; break; default: return -EINVAL; } pdev = platform_device_register_simple("mga_warp", 0, NULL, 0); if (IS_ERR(pdev)) { DRM_ERROR("mga: Failed to register microcode\n"); return PTR_ERR(pdev); } rc = request_ihex_firmware(&fw, firmware_name, &pdev->dev); platform_device_unregister(pdev); if (rc) { DRM_ERROR("mga: Failed to load microcode \"%s\"\n", firmware_name); return rc; } size = 0; where = 0; for (rec = (const struct ihex_binrec *)fw->data; rec; rec = ihex_next_binrec(rec)) { size += WARP_UCODE_SIZE(be16_to_cpu(rec->len)); where++; } if (where != n_pipes) { DRM_ERROR("mga: Invalid microcode \"%s\"\n", firmware_name); rc = -EINVAL; goto out; } size = PAGE_ALIGN(size); DRM_DEBUG("MGA ucode size = %d bytes\n", size); if (size > dev_priv->warp->size) { DRM_ERROR("microcode too large! (%u > %lu)\n", size, dev_priv->warp->size); rc = -ENOMEM; goto out; } memset(dev_priv->warp_pipe_phys, 0, sizeof(dev_priv->warp_pipe_phys)); where = 0; for (rec = (const struct ihex_binrec *)fw->data; rec; rec = ihex_next_binrec(rec)) { unsigned int src_size, dst_size; DRM_DEBUG(" pcbase = 0x%08lx vcbase = %p\n", pcbase, vcbase); dev_priv->warp_pipe_phys[where] = pcbase; src_size = be16_to_cpu(rec->len); dst_size = WARP_UCODE_SIZE(src_size); memcpy(vcbase, rec->data, src_size); pcbase += dst_size; vcbase += dst_size; where++; } out: release_firmware(fw); return rc; }
#define MGA_WARP_CODE_ALIGN 256 /* in bytes */ #define WARP_UCODE_SIZE( which ) \ ((sizeof(which) / MGA_WARP_CODE_ALIGN + 1) * MGA_WARP_CODE_ALIGN) #define WARP_UCODE_INSTALL( which, where ) \ do { \ DRM_DEBUG( " pcbase = 0x%08lx vcbase = %p\n", pcbase, vcbase );\ dev_priv->warp_pipe_phys[where] = pcbase; \ memcpy( vcbase, which, sizeof(which) ); \ pcbase += WARP_UCODE_SIZE( which ); \ vcbase += WARP_UCODE_SIZE( which ); \ } while (0) static const unsigned int mga_warp_g400_microcode_size = (WARP_UCODE_SIZE(warp_g400_tgz) + WARP_UCODE_SIZE(warp_g400_tgza) + WARP_UCODE_SIZE(warp_g400_tgzaf) + WARP_UCODE_SIZE(warp_g400_tgzf) + WARP_UCODE_SIZE(warp_g400_tgzs) + WARP_UCODE_SIZE(warp_g400_tgzsa) + WARP_UCODE_SIZE(warp_g400_tgzsaf) + WARP_UCODE_SIZE(warp_g400_tgzsf) + WARP_UCODE_SIZE(warp_g400_t2gz) + WARP_UCODE_SIZE(warp_g400_t2gza) + WARP_UCODE_SIZE(warp_g400_t2gzaf) + WARP_UCODE_SIZE(warp_g400_t2gzf) + WARP_UCODE_SIZE(warp_g400_t2gzs) + WARP_UCODE_SIZE(warp_g400_t2gzsa) + WARP_UCODE_SIZE(warp_g400_t2gzsaf) + WARP_UCODE_SIZE(warp_g400_t2gzsf));